**
位运算
**
位运算的基本知识
- c语言可以按二进制位进行计算,它只适用于整型或字符型数据
- 位运算用补码进行运算,正数的补码就是原码,负数的补码为原码取反加1;计算得出的结果如果是正数,就直接等于补码,若是负数则需减1取反,取反时符号位不变。
位运算的运算符
位运算的运算符有以下6种:
1 - 按位与(&):位与运算符“&”是双目运算符
- 与运算的规则是:只有当对应的两个二进制位都为1时,运算结果中该位才是1,否则,该位是0.
- 例如,求7&5,7的二进制数为00000111,5的二进制数为00000101;
7的二进制 00000111
5的二进制 00000101
最终结果为00000010 - 用途:按位与运算通常用于二进制取位操作,例如一个数&1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数
2.按位或(|):位或运算符“|”是双目运算符
- 或运算的规则是:只有当对应的两个二进制位都为0时,运算结果中该位才是0,否则,该位是1。
- 例如:求13|21
13的二进制为00001101
21的二进制为00010101
最终的结果为 00011101
用途:一个数 | 1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数 | 1之后再减一就可以了,按位或运算常用来对一个数据的某些位定值为1
3.按位异或(^):异或运算符“ ^ ”是双目运算符
- 异或运算的规则是:只有当对应的两个二进制位不同时,运算结果中该位才是1,否则,该位是0,即相同为0,不同为1.
- 例如:求13^12
13的二进制为00001101
21的二进制为00010101
最终的结果为 00011000 - 用途:异或运算可以用来使操作数的某些位翻转(方法是将该位和1进行异或运算),或者保留某些位(方法是将该位和0进行异或运算)
4.位反运算符(~):位反运算符“ ~”是单目运算符
-
位反的运算规则是:将所有操作数按位取反,包括符号位(如果是负数减1取反,则取反时符号位不变),即0变成1,1变成0;
-
例如:求~13
13的二进制为00001101
取反后结果为 11110010
5.位左移运算符(<<):位左移运算符“<<”是双目运算符
- 使用格式: 操作数<<位数
- 功能是:将一个操作数按指定的位数左移,左移时,从左边移出的高位部分被丢弃,右边空出的低位部分补0;
- 例如:a=3;
b=a<<1;计算结果为b=6;
b=a<<2;计算结果为b=12;
由此也可得出,左移一位,相当于该数乘以2,左移n位,相当于该数乘以2n
6.位右移运算符(>>):位右移运算符“>>”是双目运算符
-
使用格式:操作数>>位数
-
功能是:将一个操作数按指定的位数右移,右移时,从右边移出的高位部分被丢弃,左边空出的高位部分补0还是补1,按下面的规则处理
1.若操作数是无符号的,右移时,高位补0;
2.若操作数是有符号的,右移时,在高位补符号位,即正数补0,负数补1 例 -
如:a=9;
b=a>>1;计算结果为b=4;
b=a>>2,计算结果为b=2;
由此也可得出,右移一位,相当于该数除以2,右移n位,相当于该数除以2n
纸质月考核后半段关于位运算的例题:
#include <stdio.h>
int main()
{
int a = 10, b = -25;
int c = 0, d = 3;
int e = 20;
printf("%d\n", (a << 2)); // 1
printf("%d\n", (b >> 3)); // 2
printf("%d\n", (b = c)); // 3
printf("%d\n", (a & b)); // 4
printf("%d\n", (a ^ b)); // 5
printf("%d\n", (a | b)); // 6
printf("%d\n", (~b)); // 7
printf("%d\n", (b >>= 3)); // 8
printf("%d\n", (a <= b <= c)); // 9
printf("%d\n", (b >> a - 4)); // 10
printf("%d\n", (a & 0x1 == b & 0x1)); // 11
printf("%d\n", (a | b << ++a > b)); // 12
printf("%d\n", (! ~ b++)); // 13
printf("%d\n", (a - b, c += d, e - c)); // 14
printf("%d\n", (a <<=3 > 0)); // 15
printf("%d\n", (a <<= d > 20 ? b && c++ : d--)); // 16
return 0;
}
题解:
1.(a<<2)
a的二进制数为00001010,使a左移两位00 001010(00),删除左边两位,在右边空出的两位补0,最后答案为40
2.(b>>3)
b的二进制数为11100111,使b右移两位(111)11100 111 删除右边的三位,在左边空出的三位补1,因为原数带符号,所以补1,最后答案为-4
3.(b=c)
对b赋值为c,b=0
4.(a & b)
a的二进制数为00001010
b的二进制数为00000000
答案--------------00000000
为0
5.(a ^ b)
a的二进制数为00001010
b的二进制数为10000000
答案--------------10001010
为10
6.(a | b)
a的二进制数为00001010
b的二进制数为00000000
答案-------------00001010
为10
可以看出,任何数 & 0结果都为0,任何数^0都为它本身,任何数 | 0都为它本身
7.(~b)
b的二进制数为00,取反时符号位也要取反所以变为11,答案是-1.
8.(b>>=3)
b=b>>3,>>的优先级先于=
所以先计算右移三位,(000)011
答案为0,再将此值赋给b,得到最终答案0
9.(a<=b<=c)
按从左到右的顺序开始判断a<=b,a=10>b,所以此语句为假,0<c,所以后半句语句为真,返回1,所以最终答案为1
10.(b>>a-4)
-的优先级在>>前
所以先计算a-4=6,再让b>>6,
b的值为0,右移三位结果仍未0
11.(a&0x1== b&0x1)
0x1是指十六进制中的1, == 的优先级在&前,
所以 a&0x1== b&0x1 等价于a&(1==b)&1
b!=0,所以括号内条件为假(0),最终整个式子变为a&0&1,结果为0
12.(a | b << ++a > b)
++先于<<先于>先于|
所以由a | b << 11 > b(a | b << (++a )> b)
变为 a|0>b (a | (b << 11 )> b)
变为 a|0 ,
最终结果为11
13.(!~b++)
++先于~先于!
所以先计算!~ 1,(!~(b++)),
变为 !-2, ( ! (~1));
结果为0
1按位取反的结果为1111 1111 1111 1110;以1开头说明是个负数,该数按位取反在加一得到的结果 2 在加上负号就是-2
14.(a-b , c+=d , e-c)
逗号运算符从左向右依次计算,最终值取最右边的式子
(a-b,c+=d,e-c)
(10 ,c = 3 , 17)
整个式子最终答案取17,但c同时也被赋值为3
15.(a<<=3>=0)
">=“先于”<<="
所以先计算3>=0,答案为1,
再计算a<<=1,a<<=1同为a=a<<1,
a的二进制为00001011,左移一位,0 0001011(0),
结果为22
16.(a<<=d>20?b&&c++:d–)
++,-- 先于>先于 && 先于 ?:先于 <<=
首先计算出(a <<= d > 20 ? b && 3 : 3)
然后(a <<=( d > 20) ? b &&3 : 3)
之后(a <<=0 ?( b &&3) : 3)
再然后(a <<=(0 ?0 : 3))
最后(a <<=3)
a的二进制为00010110,左移三位,000 10110000
结果为176.