背景

“反码”“取反”“按位取反(~)”,这3个概念是不一样的。

  • 取反:逻辑非“!”,逻辑取反, false变true,true变false,在C中,只要不是0就是真,所以!5值是0
  • 反码:正数的反码是其本身,对于负数其符号位不变其它各位取反(0变1,1变0)
  • 按位取反(~): 按位取反1变0,0变1。

要弄懂这个运算符的计算方法,首先必须明白二进制数在内存中的存放形式,二进制数在内存中是以补码的形式存放的。

另外正数和负数的补码不一样,正数的补码、反码都是其本身,负数的反码等于原码符号位不变,其余各位取反,负数的补码等于反码末位加1

正数9:

取原码: 0000 1001
取补码: 0000 1001
取反码: 0000 1001
内存中存放格式 0000 1001
再例如: -2

取原码: 1000 0010 (最高位1表示符号位)
取反码: 1111 1101 (符号位不变,其余各位求反)
取补码: 1111 1110 (反码末位+1)

内存中存放格式: 1111 1110

计算原理

弄懂了上述情况后,按位取反如何计算就好办了

假设要对正数9按位取反——> (~9),计算步骤如下:

取原码 0000 1001,
取反码 0000 1001,
取补码 0000 1001,
对其取反 1111 0110(符号位一起进行取反,这不是最终结果,只是补码的取反仅此而已)
接上面对 0000 1001 取反后得到 1111 0110,由于计算机需要以补码表示,需要对该值获取补码才能获得最终结果

取原码:1111 0110
取反码:1000 1001 (符号位不变,其余各位求反)
取补码:1000 1010 (反码+1)
最终结果是 1000 1010,也就是-10

再对正数5按位取反——> (~5),计算步骤如下:

原码,反码,补码皆为 0000 0101

对其取反 1111 1010(符号位一起进行取反) 

取反码:1000 0101(符号位不变,其余各位求反)

取补码:1000 0110 (反码+1)

最终结果 1000 0110 ,也就是-6

下面我们再计算 (~ -10)

-10的原码:1000 1010  

-10的反码:1111  0101 (符号位不变)

-10的补码:1111 0110 (反码+1)

补码取反:0000 1001 (符号位一起取反)

正好得到一个正数,那么对其求原码就可得到最终结果

再因正数的补码,反码,原码都一样,最终结果是 0000 1001 ,正好是9的二进制。

0的按位取反是 -1(0在数学界既不是正数也不是负数)  
假设要对正数0按位取反——> (~0),计算步骤如下:

取原码 0000 0000,
取反码 0000 0000,
取补码 0000 0000,
对0000 0000的反码取反后得到 1111 1111(符号位一起进行取反,这不是最终结果,只是补码的取反仅此而已),由于计算机需要以补码表示,需要对1111 1111该值获取补码才能获得最终结果

取原码:1111 1111
取反码:1000 0000 (符号位不变,其余各位求反)
取补码:1000 0001 (反码+1)
最终结果是 1000 0001,也就是-1

总结

1. 所有正整数的按位取反是其本身+1的负数

2. 所有负整数的按位取反是其本身+1的绝对值