1. C语言中的位运算符——直接对bit位进行操作,效率最高
& |
按位与 |
| |
按位或 |
^ |
按位异或 |
~ |
取反 |
<< |
左移 |
>> |
右移 |
2. 左移和右移注意点
(1)左操作数必须为整型类型:char和short被隐式转换为int后进行移位操作
(2)右操作数的范围必须为:[0,31]。其他值属未定义行为,不同编译器处理不同。
(3)左移运算符 << 将运算数的二进制位左移:规则为高位丢弃,低位补0
(4)右移运算符 >> 把运算数的二进制位左移:规则为高位补符号,低位丢弃
3. 有趣的问题:0x1 << 2 + 3 的值会是什么?
【实例分析】位运算符初探
#include <stdio.h> int main() { printf("%d ", 3 << 2); //3<<2 ===> 0x11<<2 ===>1100,即12 printf("%d ", 3 >> 1); //0x11<<1, 即1 printf("%d ", -1 >> 1);//0x1111>>1 ,即0x1111,仍为1 printf("%d ", 0x01 << 2 + 3);//相当于0x01<<(2+3),即32 printf("%d ", 3 << -1); // oops!右操作数必须为[0,31],不同编译器处理方式不同 return 0; }
4. 小贴士——防错准则
(1)避免位运算符、逻辑运算符和数学运算符同时出现在一个表达式中
(2)当位运算符,逻辑运算符和数学运算符需要同时参与运算时,尽量使用括号()表达达计算次序。
【小技巧】
①左移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 ", a); printf("b = %d ", b); SWAP3(a ,b); printf("a = %d ", a); printf("b = %d ", b); return 0; }
5. 位运算与逻辑运算不同
(1)位运算没有短路规则,每个操作数都参与运算
(2)位运算的结果为整数,而不是0或1
(3)位运算符优先级高于逻辑运算优先级
【实例分析】混淆概念的判断条件
使用了位运算符作为判断条件(错误) | 使用逻辑运算符作为判断条件(正确) |
#include <stdio.h> int main() { int i = 0; int j = 0; int k = 0; //注意位运算,不会短路 if( ++i | ++j & ++k ) { printf("Run here... "); } printf("i = %d ", i); //1 printf("j = %d ", j); //1 printf("k = %d ", k); //1 return 0; } |
#include<stdio.h> int main() { int i = 0; int j = 0; int k = 0; //注意是逻辑运算,短路 if (++i || ++j && ++k) //&&优先高于|| { printf("Run here... "); } printf("i = %d ", i); //1 printf("j = %d ", j); //0 printf("k = %d ", k); //0 return 0; } |
6. 小结
(1)位运算符只能用于整数类型
(2)左移和右移运算符的右操作数范围必须为[0,31]
(3)位运算的没有短路规则,所有操作数均会求值。
(4)位运算的效率高于四则运算和逻辑运算
(5)运算优先级: 四则运算 > 位运算 > 逻辑运算