第16课 - 位运算符分析
第16课 - 位运算符分析
1. C语言中的位运算符
C语言中的位运算符直接对 bit 位进行操作,其效率最高。
2. 左移和右移运算符的注意点
(1)左操作数必须为整型类型即char、short、int,其中char和short被隐式转换为int后进行移位操作。其它的数据类型,如float等不能进行移位操作。
(2)C标准规定右操作数的范围为[0,31],如果右操作数不在该范围内,其行为是未定义的,不同的编译器处理方式不同。
(3)左移运算符 << 将运算数的二进制位左移
规则:高位丢弃,低位补0
(4)右移运算符 >> 将运算数的二进制位右移
规则:高位补符号位(正数补0,负数补1),低位丢弃
(5)0x1 << 2 + 3 的值是什么?是1左移两位之后的值4 + 3 = 7吗? ==> 注意,+ 的优先级大于 << 和 >> 的优先级,即0x1 << 5 等于32
(6)左移n位相当于乘以2的n次方,但效率比数学运算符高;右移n位相当于除以2的n次方,但效率比数学运算符高
【位运算符初探】
1 #include <stdio.h> 2 3 int main() 4 { 5 printf("%d\n", 3 << 2); // 3 << 2 ==> 11 << 2 ==> 1100,即12 6 printf("%d\n", 3 >> 1); // 11 >> 1,即1 7 printf("%d\n", -1 >> 10); // -1 >> 10 ==> 11111111 11111111 11111111 11111111 >> 10 ==> 11111111 11111111 11111111 11111111 ,即0xffffffff,仍为-1 8 printf("%d\n", 0x01 << 2 + 3); // 相当于0x01 << (2+3),即32 9 10 printf("%d\n", 3 << -1); // oops! 右操作数取值范围为[0,31],-1不在该范围内,不同编译器处理方式不同 11 // 使用gcc编译,结果为1(将左移-1位当做右移1位,3右移1位结果为1); 使用VS2010编译,结果为0(不符合C标准直接输出0); 使用bcc32编译,结果为-2147483648(int类型的最小值,提醒程序员用法错误) 12 return 0; 13 }
使用gcc编译执行上述代码
※※ 避免位运算符、逻辑运算符和数学运算符同时出现在一个表达式中,如果确实需要同时参与运算,尽量使用括号( )来表达计算次序。
3. 交换两个整型变量的值
下面再介绍一下使用位运算符交换两个变量的值。
1 #include <stdio.h> 2 3 // 使用中间变量交换 4 #define SWAP1(a, b) \ 5 { \ 6 int t = a; \ 7 a = b; \ 8 b = t; \ 9 } 10 11 // 使用部分和交换 12 #define SWAP2(a, b) \ 13 { \ 14 a = a + b; \ // a + b 的值不能溢出 15 b = a - b; \ 16 a = a - b; \ 17 } 18 19 //使用异或 ^ 交换 20 #define SWAP3(a, b) \ 21 { \ 22 a = a ^ b; \ 23 b = a ^ b; \ 24 a = a ^ b; \ 25 } 26 27 int main() 28 { 29 int a = 1; 30 int b = 2; 31 32 33 printf("a = %d\n", a); 34 printf("b = %d\n", b); 35 36 SWAP3(a ,b); 37 38 printf("a = %d\n", a); 39 printf("b = %d\n", b); 40 41 return 0; 42 }
swj@ubuntu:~/c_course/ch_16$ ./a.out
a = 1
b = 2
a = 2
b = 1
4. 位运算与逻辑运算
(1)位运算没有短路规则,每个操作数都参与运算
(2)位运算的结果为整数,而不是 0 或 1
(3)位运算的优先级高于逻辑运算的优先级
【混淆概念的判断条件】
位运算
1 #include <stdio.h> 2 3 int main() 4 { 5 int i = 0; 6 int j = 0; 7 int k = 0; 8 9 // 位运算没有短路规则,所有操作数都参与运算 10 if( ++i | ++j & ++k ) 11 { 12 printf("Run here...\n"); 13 } 14 15 printf("i = %d\n", i); // 1 16 printf("j = %d\n", j); // 1 17 printf("k = %d\n", k); // 1 18 19 return 0; 20 }
逻辑运算
1 #include <stdio.h> 2 3 int main() 4 { 5 int i = 0; 6 int j = 0; 7 int k = 0; 8 9 // 短路规则, (true && ++i) || (++j && ++k) 10 if( ++i || ++j && ++k ) 11 { 12 printf("Run here...\n"); 13 } 14 15 printf("i = %d\n", i); // 1 16 printf("j = %d\n", j); // 0 17 printf("k = %d\n", k); // 0 18 19 return 0; 20 }