文章目录
一、位运算符分析
二、小贴士
三、位运算与逻辑运算
四、小结
一、位运算符分析
????????位运算符直接对 bit 位进行操作,其效率最高。
- 左移和右移注意点
- 左操作数必须为整数类型
- char 和 short 被隐式转换为 int 后进行移位操作
- 右操作数的范围必须为:[0,31]
- 左移运算符?<< 将运算数的二进制位左移
- 右移运算符?>> 把运算数的二进制位右移
? ? ? ? 下面一段代码:
#include <stdio.h>
int main()
{
printf("%d\n", 3 << 2);
printf("%d\n", 3 >> 1);
printf("%d\n", -1 >> 1);
printf("%d\n", 0x01 << 2 + 3);
printf("%d\n", 3 << -1); // oops!
return 0;
}
? ? ? ? 下面为输出结果:
? ? ? ? ?注意四则运算优先级大于位运算,所以 0x01 << 2 + 3 的结果是 32。 还有就是右操作数的范围必须为:[0,31],如果不在这个范围内,程序的输出结果由不同类型的编译器所决定,结果将不确定,就像本代码 3 << -1 一样。
二、小贴士
- 防错准则:
- 避免位运算符,逻辑运算符和数学运算符同时出现在一个表达式中
- 当位运算符,逻辑运算符和数学运算符需要同时参与运算时,尽量使用括号 ( ) 来表达计算次序
- 小技巧:
- 左移 n 位相当于乘以 2 的 n 次方,但效率比数学运算符高
- 右移 n 位相当于除以 2 的 n 次方,但效率比数学运算符高
? ? ? ? 下面看一段交换两个整型变量值的代码:?
#include <stdio.h>
#define SWAP1(a,b) \
{ \
int t = a; \
a = b; \
b = t; \
}
#define SWAP2(a,b) \
{ \
a = a + b; \
b = a - b; \
a = a - b; \
}
#define SWAP3(a,b) \
{ \
a = a ^ b; \
b = a ^ b; \
a = a ^ b; \
}
int main()
{
int a = 1;
int b = 2;
//printf("a = %d\n", a);
//printf("b = %d\n", b);
SWAP1(a,b);
printf("a = %d\n", a);
printf("b = %d\n\n", b);
a = 1;
b = 2;
SWAP2(a,b);
printf("a = %d\n", a);
printf("b = %d\n\n", b);
a = 1;
b = 2;
SWAP3(a,b);
printf("a = %d\n", a);
printf("b = %d\n\n", b);
return 0;
}
? ? ? ? ?第一种方法需要引入第三方变量,第二种方法可能会导致越界问题,第三种的方法效率较高,且不用引入第三方变量。
? ? ? ? 注意第三种方法:执行 a = a ^ b; 后,b = a ^ b; 就相当于 b = a ^ b ^ b; 先计算后面的,就是 b = a ^ 0,结果就是 b = a;再执行??a = a ^ b;相当于 a = a ^ b ^ b,即 a = a ^ b ^ a,显然结果是 b。
? ? ? ? 小知识:
????????A 异或 0 等于 A ,A 异或 1 等于 非A。
三、位运算与逻辑运算
- 位运算与逻辑运算不同:
- 位运算没有短路规则,每个操作数都参与运算
- 位运算的结果为整数,而不是 0 或 1
- 位运算优先级高于逻辑运算优先级
? ? ? ? 下面再来看一个混淆改变的判断条件:
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
int k = 0;
if( ++i | ++j & ++k )
{
printf("Run here...\n");
}
printf("i = %d, j = %d, k = %d\n\n", i, j, k);
i = 0;
j = 0;
k = 0;
if( ++i || ++j && ++k )
{
printf("Run here...\n");
}
printf("i = %d, j = %d, k = %d\n\n", i, j, k);
return 0;
}
? ? ? ? 下面为输出结果:?
? ? ? ? ?可以看到,如果错把?++i || ++j && ++k 写成??++i | ++j & ++k,虽然都能运行,但是其中的执行细节不一样,在实际工程中可能会出现 bug,而且还不好排查。
四、小结
- 位运算符只能用于整数类型
- 左移和右移运算符的右操作数范围必须为 [0,31]
- 位运算没有短路规则,所有操作数均会求值
- 位运算的效率高于四则运算和逻辑运算
- 运算优先级:四则运算 > 位运算 > 逻辑运算
?
|