3.7 位运算(二进制位运算)
3.7.1 &按位与
语法:全1为1 有0为0
特点:和1相与保持不变 和0相与为0
场景:将指定位清0
1100 0011
& 1111 1111
--------------
1100 0000
案例1:data为1字节 将data的第3,4位清0 其他位保持不变
usinged char data;
data = data & 1110 0111;
data = data & 0xe7;//ok
data &= 0xe7;//ok
3.7.2 |按位或
语法:有1为1 全0为0
特点:和1或置1,和0或保持不变
场景:将指定位置1
1100 0011
| 1111 0000
--------------
1111 0011
案例1:data为1字节 将data的第5,6位置1 其他位保持不变
data = data | 0110 0000
data = data | 0x60;//ok
data |= 0x60;//ok
3.7.3 ~按位取反
语法:0变1 1变0
-1100 0011 == 0011 1100
3.7.4 ^按位异或
语法:相同为0 不同为1
特点:和1异或取反 和0异或保持不变
场景:将指定位 发生翻转
1100 0011
^ 1111 0000
----------------
0011 0011
^ 1111 0000
----------------
1100 0011
3.7.5 左移<<:左边丢弃 右边补0
移动的位数 不要超过自身的宽度
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJO24ybY-1678325646037)(./images/2023-02-15 17-43-58屏幕截图.png)]
如果:data=0000 0001 data=data<<0; data=0000 0001 == 1 ==data*2^0
如果:data=0000 0001 data=data<<1; data=0000 0010 == 2 ==data*2^1
如果:data=0000 0001 data=data<<2; data=0000 0100 == 4 ==data*2^2
如果:data=0000 0001 data=data<<3; data=0000 1000 == 8 ==data*2^3
......
如果:data=0000 0001 data=data<<6; data=0100 0000 == 64 ==data*2^6
3.7.6 右移>>:右边丢弃 左边补0(补1)
算术右移、逻辑右移 都是编译器决定,用户无法确定
无符号数:右边丢弃 左边补0
有符号数:
正数:右边丢弃 左边补0
负数:右边丢弃 左边补0(逻辑右移)
负数:右边丢弃 左边补1(算术右移)
案例1:编写代码测试 编译器为那种右移:
假设data为无符号数
如果:data=1000 0000 data=data>>0; data=1000 0000 == 128==data除以2^0
如果:data=1000 0000 data=data>>1; data=0100 0000 == 64==data除以2^1
如果:data=1000 0000 data=data>>2; data=0010 0000 == 32==data除以2^2
如果:data=1000 0000 data=data>>3; data=0001 0000 == 16==data除以2^3
......
如果:data=1000 0000 data=data>>6; data=0000 0010 == 2==data除以2^6
3.7.7 位运算的综合应用
案例1:data为1字节 将data的第3,4为清0 其他位保持不变
data = data & 1110 0111
1110 0111 == ~(0001 1000) == ~(0001 0000 | 0000 1000)
==~(0000 0001<<4 | 0000 0001<<3)
==~(0x01<<4 | 0x01<<3);
data &= ~(0x01<<4 | 0x01<<3);//推荐
案例2:data为1字节 将data的第5,6位置1 其他位保持不变
data = data | 0110 0000
0110 0000==0100 0000 | 0010 0000==0000 0001<<6 | 0000 0001<<6|0000 0001<<5
==0x01<<6 | 0x01<<5
data |=(0x01<<6|0x01<<5);//推荐