C 位运算
移位操作符
移位操作只是简单地把一个值的位向左或向右移动。在左移位中,右边多出来的几个空位则由0补齐。若有位移出左边界,则丢弃。
>> | 左移 |
>> | 右移 |
例1.0
int a = 25;/*25的二进制形式:000011001*/
printf("%d\n", a << 2);/*向左移2位得:001100100,即十进制形式的100*/
printf("%d\n", a << 28);
/*
向左移28位,移出左边界的位丢失
得到:1001 0000 0000 0000 0000 0000 0000 0000
*/
由此,可以用a << n代替a * pow(2,n);
实际使用时,请注意避免数值溢出,例如32位的25而言,若左移27位,符号位由1变为0,结果将变成负数
右移位分为逻辑移位和算术移位
- 逻辑移位左边空出的位置用0填充;
- 算术移位填充值又符号位决定:
若符号位为1,空位均填1;
若符号位为0,空位均填0;
例1.1
int a = 25;/*25的二进制形式(省略前面的24位):000011001*/
printf("%d\n", a >> 2);/*向右移2位得:000000110,即十进制形式的6*/
例1.2
int a = -25;
/*
-25的二进制补码形式:
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11100111
*/
printf("%d\n", a >> 2);
/*
向右移2位得:
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111001
即十进制形式的-7
*/
同样的,可以用a >> n代替a / pow(2,n);
实际使用的时只能用于正数。
位操作符
例2.0
int a = 25, b = 24;
/*
25的二进制形式(省略前面的24位):
000011001
24的二进制形式(省略前面的24位):
000011000
*/
printf("%d\n", a & 1);
/*
000011001
& 000000001
——————————————
000000001
*/
printf("%d\n", b & 1);
/*
000011000
& 000000001
——————————————
000000000
*/
对于一个奇数,它的二进制数的最后一位总是1,而对于一个偶数,它的二进制数最后一位总是0。
由此,我们找到了一个新的判断一个数是否是偶数的方法,
if( x & 1 == 0 ){
printf("%d是偶数\n", x);
}else{
printf("%d不是偶数\n", x);
}
例2.1
int a = 24, b = 23;
/*
24的二进制形式(省略前面的24位):
000011000
23的二进制形式(省略前面的24位):
000010111
*/
printf("%d\n", a | b);
/*
000011000
| 000010111
——————————————
000011111
即十进制的31
*/
例2.2
int a = 24, b = 23;
/*
24的二进制形式(省略前面的24位):
000011000
23的二进制形式(省略前面的24位):
000010111
*/
printf("%d\n", a ^ b);
/*
000011000
^ 000010111
——————————————
000001111
即十进制的15
*/
例2.3
int a = 25;
/*
25的二进制形式:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00011001
*/
printf("%d\n", ~a);
/*
~ 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00011001
————————————————————————————————————————————————————————————————————————————
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11100110
*/
位运算中的复合赋值符号
a <<= 2和a = a << 2等价,以此类推
移位操作符和位操作符结合使用可以用来操纵一个整型值中的单个位
例3.0
/*将指定的位设置为1*/
int a = 25;
int bit_number = 2;
a |= 1 << bit_number;
/*
000011001
| 000000100
——————————————
000011101
*/
例3.1
/*将指定的位设置为0*/
int a = 25;
int bit_number = 3;
a &= ~(1 << bit_number);
/*
~ 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00001000
————————————————————————————————————————————————————————————————————————————
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11110111
000011001
& 111110111
——————————————
000010101
*/
例3.2
/*
将
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00011001
变换为
10011000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
*/
#include <stdio.h>
int
main( void )
{
int a = 25;
int b = 10;
int c;
c = a ^ b;
c <<= 27;
return 0;
}
思路:
首先明确需要左移位操作,但在左移之前先将00011001变换成00010011
1.列出变换算式
/*
00011001
运算符 中间值
—————————————————
00010011
*/
得到运算符为^,中间值为10。
2.执行左移操作,完成。
例3.3
/*
清零操作
*/
int a = 1;
a ^= a;
例3.4
//不使用其他变量交换a, b的值
a = a ^ b;
b = b ^ a;
a = a ^ b;