前言
此文主要为了本人复习知识
在学习位操作时,我们首先要清楚的是:
1.位运算的符操作数只能是整型和字符型对象
2.在计算机中数据都是以二进制存储的(位操作就是直接对二进制进行操作)
原码、反码、补码,这是学习位操作必不可少的知识
一、原码、反码、补码
整数以二进制补码的形式存储在内存中,对于正数的:原码、反码、补码
都相同,以下规则针对负整数。
原码:根据数值写出的二进制序列
反码:以原码为基础,原码符号位不变其他位按位取反(按位取反:0变1,1变0)
补码:在反码的基础上加1
下面我们看示例(对应上面规则来看)
例:正整数1
原码:00000000 00000000 00000000 00000001
反码:00000000 00000000 00000000 00000001
补码:00000000 00000000 00000000 00000001
负整数1(-1)
原码:10000000 00000000 00000000 00000001
反码:11111111 11111111 11111111 11111110(按位取反,符号位不变)
补码:11111111 11111111 11111111 11111111( 反码 + 1)
二、按位逻辑运算符
1、按位取反:~
这里按位取反符号位也改变
例:a=1(有符号整型)
一定要写个代码跑一跑
代码:
int a = 1;
printf("%d",~a)
a=1
补:00000000 00000000 00000000 00000001
~a
补:11111111 11111111 11111111 11111110(可以看到对1,取反后得到的补码,符号位为1)
我们要想得到它的值,需要先将补码转换为原码
反:11111111 11111111 11111111 11111101
原:10000000 00000000 00000000 00000010(结果为-2)
a=1(无符号整型)
代码:
size_t a = 1;//无符号整型
printf("%zu",~a);
a=1
补:00000000 00000000 00000000 00000001
~a
补:11111111 11111111 11111111 11111110(因为不含符号位,得到的就是正整数,即补码就是原码)
2.按位与:&
二元运算符&通过逐位比较两个运算对象, 生成一个新值。对于每个位,只有两个运算对象中相应的位都为1时,结果才为1(从真/假方面看,只有当两个位都为真时,结果才为真----计算机0为假,非零为真)。
例:
a=1:
补:00000000 00000000 00000000 00000001
b=-1:
补:11111111 11111111 11111111 11111111
a&b:
00000000 00000000 00000000 00000001
&
11111111 11111111 11111111 11111111
结果:
00000000 00000000 00000000 00000001(1)
3、按位或:|
二元运算符|,通过逐位比较两个运算对象,生成一个新值。对于每个位,如果两个运算对象中相应的位为1,结果就为1(从真/假方面看,如果两个运算算对象中相应的一个位为真或两个位都为真,那么结果为真)。
例:
a=1:
补:00000000 00000000 00000000 00000001
b=-1:
补:11111111 11111111 11111111 11111111
a&b:
00000000 00000000 00000000 00000001
|
11111111 11111111 11111111 11111111
结果:
补:11111111 11111111 11111111 11111111
原:10000000 00000000 00000000 00000001(-1)
4、按位异或:^
二元运算符^逐位比较两个运算对象。对于4每个位,如果两个运算对象中相应的位一个为1(但不是两个为1),结果为1(从真/假方面看,如果两个运算对象中相应的一个位为真且不是两个为同为1,那么结果为真)。
例:
a=1:
补:00000000 00000000 00000000 00000001
b=-1:
补:11111111 11111111 11111111 11111111
a&b:
00000000 00000000 00000000 00000001
^
11111111 11111111 11111111 11111111
结果:
补:11111111 11111111 11111111 11111110
原:10000000 00000000 00000000 00000010(-2)
可以想影响如果两个相同的数进行异或,它的结果不就是0了吗
5、左移(<<)、右移(>>)
该操作产生了一个新的位值,但是不改变其运运算对象,类似与+、-等操作符,要想获得操作后
的结果可以配合赋值符使用。
a=-3:
补:11111111 11111111 11111111 11111101
a<<1
补:11111111 11111111 11111111 11111010
原:10000000 00000000 00000000 00000110(-6)
a>>1
补:11111111 11111111 11111111 11111110
原:10000000 00000000 00000000 00000010(-2)
总结
需要注意的是对于负整数,原码、反码、补码之间的转化,和有符号、无符号之间的差异;其实这一块并没有难度,主要理解后灵活使用,下面是关于这方面的例题:
1、只出现一次的数i
2、只出现一次的数ii
3、只出现一次的数iii