位运算符简介
位运算符直接对bit位进行操作,其效率最高,C语言支持以下位运算符。
| 位运算符 | 作用 |
|---|---|
| & | 按位与 |
| \ | 按位或 |
| ^ | 按位异或 |
| ~ | 按位取反 |
| << >> | 左右移运算 |
| <<< >>> | 左右移运算 |
左右移运算的规则
左操作数必须为整形类型,不能为浮点类型,char和short被隐式转换为int后进行以为操作。
右操作数的范围必须为[0, 31]之间的整数。
以上是标准C规范的定义,不同编译器可能有不同的实现,比如某些编译器循序右操作数范围为32,某些编译器下右操作数为负数也能够编译通过,这种情况应尽量避免。
左移运算符<<将运算数的二进制位左移,规则是高位丢弃,低位补0。
右移运算符>>将运算数的二进制位右移,规则是高位补符号位,低位丢弃。
测试代码:
int main(void) {
float f = 1.0;
// printf("0x%08x\n", f << 4); // error
// printf("0x%08x\n", 0x0001 << 1.4); // error
printf("0x%08x\n", 0x0001 << 4); // 0x00000010
printf("0x%08x\n", 0x00010000 >> 4); // 0x00001000
printf("0x%08x\n", -16); // 0xfffffff0
printf("0x%08x\n", -16 >> 4); // 0xffffffff
printf("0x%08x\n", -16 >> -4); // 不同编译器的处理结果不同
printf("%d\n", 1 << 2 + 3); // 32
while (1);
}
防错准则:
避免位运算符、逻辑运算符和数学运算符同时出现在一个表达式中。当位运算符、逻辑运算符和数学运算符需要同时参与运算时,尽量使用括号()来表达计算次序。
小技巧:
左移n位相当于乘以2的n次方,但效率比数学运算符高
右移n位相当于除以2的n次方,但效率比数学运算符高
位运算与逻辑运算的区别
位运算与逻辑运算的不同:
位运算没有短路原则,每个操作数都参与运算。
位运算的结果为整数,而不是1或0。
位运算的优先级高于逻辑运算优先级。
测试代码
int main(void) {
int i = 0;
int j = 0;
int k = 0;
if (++i | ++j & ++k) {
printf("Running\n");
}
printf("i = %d, j = %d, k = %d\n", i, j, k);
int x = 0;
int y = 0;
int z = 0;
if (++x || ++y && ++z) {
printf("Running\n");
}
printf("x = %d, y = %d, z = %d\n", x, y, z);
while (1);
}
运行结果
Running
i = 1, j = 1, k = 1
Running
x = 1, y = 0, z = 0
位运算的作用
节省内存
同样的内存空间使用位运算来存储更多的信息
提高效率
由于位运算是CPU中的指令集,所以他的运算效率是最高的,可以用位运算来提高乘除法的效率
其他骚操作
使用位运算实现两个数交换值
#include <stdio.h>
#define SWAP0(a, b) { \
int temp = a; \
a = b; \
b = temp; \
}
#define SWAP1(a, b) { \
a = a + b; \
b = a - b; \
a = a - b; \
}
#define SWAP2(a, b) { \
a = a ^ b; \
b = a ^ b; \
a = a ^ b; \
}
int main(void) {
int a = 1;
int b = 3;
printf("a = %d, b = %d\n", a, b);
SWAP0(a, b);
// SWAP1(a, b);
// SWAP2(a, b);
printf("a = %d, b = %d\n", a, b);
while (1);
}
使用位运算统计二进制数0/1的数量
总结
位运算符只能用于整数类型。
右移和左移运算符的右操作数范围必须为[0, 32]
位运算没有短路原则,所有操作数均会求值。
位运算的效率高于四则运算和逻辑运算
运算优先级:四则运算 > 位运算 > 逻辑运算