计算机补码: INT_MAX 和 INT_MIN为什么绝对值不同

今天写了写代码的时候用到了 INT_MAX 和 INT_MIN, 后来查了文档发现这两个常量的绝对值不一样, 我因为直觉上就以为  INT_MIN = -INT_MAX . 所以有点想不通. 查了资料发现对于一个 32位的整型数来讲, 有符号数的范围是-2147483648~~~2147483647. 想不明白为什么负数可以表示到-2147483648也就是-2^31, 而整数只能表示到2147483647也就是2^31 -1. 进一步查资料发现其实原因在于计算机使用的是补码系统, -2147483648并不是说机器能够表示到, 而是一种人为规定, 参考网上资料(下面这段解释网上有很多16位整型的类似的转载文章, 未找到原文的出处>_<)下面给出解释:

如果以最高位为符号位,二进制原码最大为0111111111111111111111111111111=2的31次方减1=2147483647, 最小为11111111111111111111111111111111 = -2^31+1 = -2147483647, 而零有两种表示方法,即正零和负零:0000000000000000000000000000000=1000000000000000000000000000000=0, 所以,二进制原码表示时,范围是-2147483647~-0和0~2147483647,因为有两个零的存在,所以不同的数值个数一共只有2的32次方减1个,比32位二进制能够提供的2的32次方个编码少1个。但是计算机中采用二进制补码存储数据,即正数编码不变,从00000000000000000000000000000000到0111111111111111111111111111111依旧表示0到2147483647,而负数需要把除符号位以后的部分取反加1,即-2147483647的补码为1000000000000000000000000000000001。到此,再来看原码的正0和负0:00000000000000000000000000000000和10000000000000000000000000000000,补码表示中,前者的补码还是00000000000000000000000000000000,后者经过非符号位取反加1后,同样变成了00000000000000000000000000000000,也就是正0和负0在补码系统中的编码是一样的。但是,事实上,32位二进制数可以表示2的32次方个编码,而在补码中零的编码只有一个,也就是补码中会比原码多一个编码出来,这个编码就是10000000000000000000000000000000,因为任何一个原码都不可能在转成补码时变成10000000000000000000000000000000。所以,人为规定10000000000000000000000000000000这个补码编码为-2147483648。 所以,补码系统中,范围是-2147483648~2147483647.
更新, 今天在微博上看到这个:
32位的int型的取值是2147483647 到 -2147483648,但是,在C/C++语言中,你不能直接使用 -2147483648 来代替最小负数,因为它不是一个数,而是一个表达式。表达式是:“对正数2147483648取负”,所以,2147483648已经溢出了。这就是为什么INT_MIN总是定义成 (-INT_MAX – 1) 的原因。
还可以参考这个: “INT_MIN
Written on April 21, 2013