课程章节:
课程名称:物联网/嵌入式工程师
章节名称:第1周之第三讲 3-6 C语言中的运算符:位运算符、赋值复合运算符、逗号运算符和三目运算符、运算符优先级
讲师姓名:大白老师
课程内容:
位运算符
运算符 | 格式 | 功能 | 结果 |
---|---|---|---|
& | 表达式1 & 表达式2 | 按位与 | 1按位与1结果是1 1按位与0结果是0 0按位与0结果是0 速记: 都1则1,1零则0 |
❘ | 表达式1 ❘ 表达式2 | 按位或 | 1按位或0结果是1 1按位或1结果是1 0按位或0结果是0 速记: 有1则1,都0则0 |
^ | 表达式1 ^ 表达式2 | 按位异或 | 相同为0,不同为1 |
~ | ~表达式 | 按位取反 | 1变成0, 0变成1 |
运算符 | 格式 | 功能 | 结果 |
---|---|---|---|
<< | 表达式 << 位数 | 左移 | 无论是正数还是负数,左移都是对应的二进制位向左移动高位丢弃,低位补0 左移的时候,等价于将这个数据乘以2的n(移动的位)次方 |
>> | 表达式 >> 位数 | 右移 | 逻辑右移(针对无符号数据) 对应的是正数和0,逻辑右移是对应的二进制位向右移动,低位丢弃,高位补0。 算术右移(针对有符号数据): 若是数据为正数,算术右移是对应的二进制位向右移动,低位丢弃,高位补0。 若是数据为负数,算术右移是对应的二进制位向右移动,低位丢弃,高位补1。 速记: 右移,向右移动,低位丢弃,高位正数补0,负数补1 |
代码示例 位运算
#include <stdio.h>
int main()
{
unsigned char reg1 = 0x13;
unsigned char reg2 = 0x78;
unsigned char data = 0;
data = reg1 & reg2;
printf("data = %#x => %d\n",data,data);
data = reg1 | reg2;
printf("data = %#x => %d\n",data,data);
data = reg1 ^ reg2;
printf("data = %#x => %d\n",data,data);
data = ~reg1;
printf("data = %#x => %d\n",data,data);
return 0;
}
分析:
0x13 => 0001 0011
0x78 => 0111 1000
& 0001 0000 => 0x10 => 16
| 0111 1011 => 4+2+1=7 8+0+2+1=11 => 0x7b => 123
^ 0110 1011 => 4+2=6 8+0+2+1=11 => 0x6b => 107
0x13 => 0001 0011
~ 1110 1100 => 14 12 => 0xec => 236
代码示例 位运算用处
#include <stdio.h>
int main()
{
unsigned char a = 10; // 0000 1010
unsigned char b = 15; // 0000 1111 8+4+2+1
unsigned char t = 0;
// a ^ a
// 0000 1010
//^ 0000 1010
// 0000 0000
// a ^ 0
// 0000 1010
//^0000 0000
// 0000 1010
printf("a = %d b = %d\n",a,b);
a = a ^ b;
b = a ^ b; // b = (a^b) ^ b => b = a ^ 0 => b=a
a = a ^ b; // a = (a^b) ^ a => a = 0 ^ b => a=b
printf("a = %d b = %d\n",a,b);
return 0;
}
代码示例 移位运算
#include <stdio.h>
int main()
{
unsigned char reg = 3;
char a = -3;
reg = reg << 3;
printf("reg = %d\n",reg);
a = a << 3;
printf("a = %d\n",a);
a = a>>3;
printf("a = %d\n",a);
return 0;
}
分析:
3 => 2+1 => 0000 0011
-3 =>
源码:1000 0011
反码:1111 1100
补码:1111 1101
3 0000 0011
<<3 0001 1000 => 16 + 8 = 24
-3 1111 1101
<<3
补码:1110 1000
反码:1001 0111
+1 :1001 1000 => -24
补码:1110 1000
>>3
补码:1111 1101
反码:1000 0010
+1 :1000 0011 => -3
课后练习
unsigned char a = 0x58;
unsigned char b = 0xd7;
unsigned char c = 0;
要求输出下列c的值。
c = a & b,
c = a | b.
c = (a & ~b) ^ 0xf1;
要求先笔算,然后书写代码验证。
代码:
#include <stdio.h>
int main()
{
unsigned char a = 0x58;
unsigned char b = 0xd7;
unsigned char c = 0;
c = a & b;
printf("c = %#x => %d\n",c,c);// 0x50 80
c = a | b;
printf("c = %#x => %d\n",c,c);// 0xdf 223
c = (a & ~b) ^ 0xf1;
printf("c = %#x => %d\n",c,c);// 0xf9 249
return 0;
}
分析:
a = 0x58
=> 4+1=5 8 => 0101 1000
b = 0xd7
=> d7 = 13 7 => 8+4+1=13 4+2+1=7 => 1101 0111
a 0101 1000
b 1101 0111
& 0101 0000 => 0x50 => 2^6+2^4=64+16=80
| 1101 1111 => 0xdf => 2^7+2^6+2^4+2^3+2^2+2^1+2^0 = 128+64+16+8+4+2+1 = 223
a&~b
=> ~b 0010 1000
=> 0101 1000
=> & 0000 1000
=> 0xf1 => f=15 1 => 8+4+2+1=15 1 => 1111 0001
0000 1000
1111 0001
^
1111 1001 => 0xf9 => 2^7+2^6+2^5+2^4+2^3+2^0 = 128+64+32+16+8+1 = 249
赋值复合运算符
运算符 | 功能说明 | 示例 |
---|---|---|
+= | 加法赋值复合运算符 | a+=b 等价于 a = a + b |
-= | 减法赋值复合运算符 | a-=b 等价于 a = a - b |
*= | 乘法赋值复合运算符 | a*=b 等价于 a = a * b |
/= | 除法赋值复合运算符 | a/=b 等价于 a = a / b |
%= | 求余赋值复合运算符 | a%=b 等价于 a = a % b |
&= | 位与赋值复合运算符 | a&=b 等价于 a = a & b |
❘= | 位或赋值复合运算符 | a❘=b 等价于 a = a ❘ b |
^= | 位异或赋值复合运算符 | a^=b 等价于 a = a ^ b |
>>= | 位右移赋值复合运算符 | a>>=b 等价于 a = a >> b |
<<= | 位左移赋值复合运算符 | a<<=b 等价于 a = a << b |
代码示例
#include <stdio.h>
int main()
{
int a = 20,b = 10;
a += b; // a = a + b; => a = 30;
printf("a = %d\n",a); //30
a *= b; //a = a * b; => 30 * 10
printf("a = %d\n",a); //300
return 0;
}
课后练习
练习
从键盘输入两个整数,要求输出+=,-=,*=,/=的结果
代码:
#include <stdio.h>
int main()
{
int a,b,ret;
printf("请输入两个整数:\n");
scanf("%d%d",&a,&b);
printf("a = %d b = %d\n",a,b);
ret = a+=b;
printf("ret = a+=b => a = %d b = %d ret = %d\n",a,b,ret);
ret = a-=b;
printf("ret = a-=b => a = %d b = %d ret = %d\n",a,b,ret);
ret = a*=b;
printf("ret = a*=b => a = %d b = %d ret = %d\n",a,b,ret);
ret = a/=b;
printf("ret = a/=b => a = %d b = %d ret = %d\n",a,b,ret);
return 0;
}
逗号运算符和三目运算符
代码示例
#include <stdio.h>
int main()
{
int a = 10,b = 20;
int c = 0;
int ret = 0;
ret = a > b ? a+b : a-b;
printf("ret = %d\n",ret);
ret = a < b ? (a^=b ,b^=a ,a^=b) : a * b;
printf("ret = %d\n",ret);
ret = a < b ? (c = a,a = b,b = c) : a * b;
printf("ret = %d\n",ret);
return 0;
}
学习笔记:
课后练习
定义三个整数a,b,c,用户从键盘输入赋值,从小到大,排列,然后输出 [不允许使用if语句]
最终输出,a保存最小值,b保存其次,c保存最大值
例如:
用户输入 a = 30,b = 20,c = 10.要求最终保存的结果为
a = 10,b = 20,c = 30.
代码:
#include <stdio.h>
int main()
{
int a,b,c;
printf("请输入三个整数:\n");
scanf("%d%d%d",&a,&b,&c);
printf("输入:a = %d b = %d c = %d\n",a,b,c);
a > b ? (a^=b,b^=a,a^=b) : a;
a > c ? (a^=c,c^=a,a^=c) : a;
b > c ? (b^=c,c^=b,b^=c) : b;
printf("输出:a = %d b = %d c = %d\n",a,b,c);
return 0;
}
运算符优先级
运算符优先级规律
优先级 | 运算符及含义 | 结合规律 |
---|---|---|
1 | [ ] () -> 后缀++ 后缀– | 从左向右 |
2 | 前缀++ 前缀-- sizeof & * + -(负号) ~ ! | 从右向左 |
3 | 强制类型转换 | 从右向左 |
4 | * / % (算术乘除) | 从左向右 |
5 | + - (算数加减) | 从左向右 |
6 | << >> (位移) | 从左向右 |
7 | < <= > >= | 从左向右 |
8 | == != | 从左向右 |
9 | &(位逻辑与) | 从左向右 |
10 | ^(位逻辑异或) | 从左向右 |
11 | ❘ (位逻辑或) | 从左向右 |
12 | && | 从左向右 |
13 | ❘❘ | 从左向右 |
14 | ? : (三目运算符) | 从左向右 |
15 | = ^= /= %= += -= <<= >>= &= ^= != | 从右向左 |
16 | , (逗号运算符) | 从左向右 |
速记口诀
初等单目一二级 -> 初等运算符和单目运算符分别是第1、2优先级
乘除求余加减移 -> 这句里面的运算符全归为算术运算符,移表示移位
关系等于不等于 -> 关系运算符(< <= > >=)
按位与来异或或 -> 位运算符优先级顺序:& -> ^->l
逻辑与或条件弱 -> 逻辑运算符优先级顺序:&&->||,后面跟着优先级比较低(弱)的条件运算符
赋值逗号一点破 -> 赋值,逗号最低
课程评价:
通过了运算符学习,熟练掌握C语言中的位运算等操作。