这是一个困惑了我几年的问题,它让我对现在的教科书和老师极其不满,从我 N 年前开始摸电脑时,就几乎在每一本 C++ 教科书上都说,8 位有符号的取值范围是 - 128 到 +127,为什么不是 - 127 到 +127 呢,后来的 java,int 的取值范围,再 32 位计算,-2^31 到 +2^31-1,可是,却从来没有任何一本教科书或一个老师比我解释过这个问题。 原因没有在工作上或者是什么地方直接遇到它,所以我也一直忽略它,但心里总是有一根刺。

直到刚才!!!! 就是刚才,无聊之极,在看汇编的书时,又遇到它了,但一如以往,书上直接地,有心地,明显地绕过了这个问题,真是可恶啊。

几经周折,终于把它搞清楚了:
其实,它是计算机底层为了实现数值运算而决定的,涉及非常非常基础的原码,反码,补码知识,一般 (99.9999%) 都不会用得上。 那 0.0001%,估计也就是计算机考试了。

话说:

用 2^8 来表示无符号整数的话,全世界的理解都是 0 到 255 了,那么,有符号呢?

用最高位表示符号,0 为 +,1 为 -,那么,正常的理解就是 -127 至 +127 了。 这就是原码了,值得一提的是,原码的弱点,有 2 个 0,即 + 0 和 - 0,还有就是,进行异号相加或同号相减时,比较笨蛋,先要判断 2 个数的绝对值大小,然后进行加减操作,最后运算结果的符号还要与大的符号相同。

于是乎,反码产生了,原因。。。。略,反正,没过多久,反码就成为了过滤产物,也就是,后来补码出现了。

补码的知识不说了,只说有关 + 127 和 - 128 的。
官方的定义 [-2^(n-1),2(n-1)-1],补码的 0 没有正负之分。原因呢? 没有一本书上有说,这也是我这么火的原因,但通过思考,google,再思考,很快找到答案:

首先,难不免干点白痴般地事情,穷举一下。。。

正数,原码跟补码一样

+127, 	0111 1111 
+126, 	0111 1110 
+125, 	0111 1101 
+124, 	0111 1100 
+123, 	0111 1011 
+122,	0111 1010 
……
+4, 	0000 0100   
+3, 	0000 0011   
+2, 	0000 0010   
+1, 	0000 0001 
0,   	0000 0000 (无正负之分)

下面是负数了

值, 	原码, 		符号位不变其它取反,	+1 
-1, 	1000 0001,	1111 1110,		1111 1111
-2,  	1000 0010,	1111 1101,		1111 1110   
-3,  	1000 0011,	1111 1100,		1111 1101   
-4,  	1000 0100,	1111 1011,		1111 1100   
-5,  	1000 0101,	1111 1010,		1111 1011   
-6,  	1000 0110,	1111 1001,		1111 1010   
-7,  	1000 0111,	1111 1000,		1111 1001   
-8,  	1000 1000,	1111 0111,		1111 1000   
-9,  	1000 1001,	1111 0110,		1111 0111 
-10,  	1000 1010,	1111 0101,		1111 0110 
-11,  	1000 1011,	1111 0100,		1111 0101 
-12,  	1000 1100,	1111 0011,		1111 0100 
-13,  	1000 1101,	1111 0010,		1111 0011 
-14,  	1000 1110,	1111 0001,		1111 0010 
-15,  	1000 1111,	1111 0000,		1111 0001 
-16,  	1001 0000,	1110 1111,		1111 0000 
-17,  	1001 0001,	1110 1110,		1110 1111 
…… 
-24,  	1001 1000,	1110 0111,		1110 1000 
…… 
-99,  	1110 0011,	1001 1100,		1110 0100 
…… 
-124, 	1111 1100,	1000 0011,		1000 0100 
-125, 	1111 1101,	1000 0010,		1000 0011 
-126, 	1111 1110,	1000 0001,		1000 0010 
-127, 	1111 1111,	1000 0000,		1000 0001

看出点什么了没有?
如果没有,那么,给个提示, 再继续下去,下一个补码是什么呢?

当然是

值, 	原码, 		符号位不变其它取反,	+1 
-128, 	先略过,  	再略过, 			1000 0000

1000 0000 那么,它的原码是什么呢?

从补码求原码的方法跟原码求补码是一样的。

先保留符号位其它求反: 1111 1111, 再加 1:11000 0000, 超过了 8 位了 对,用 8 位数的原码在这里已经无法表示了。

关键就在这里,补码 1000 0000 为 -128 是不用怀疑的 (上面的穷举), 那么,回到原码处, 它的原码也是 1000 0000(超出的自动丢失), 1000 0000 在原码表示什么呢? -0, 但补码却规定 0 没有正负之分 转换一下思路,看看计算机里,是怎么运算的:

对于负数,先取绝对值,然后求反,加一

-128 -> 128 -> 1000 0000 -> 0111 1111 -> 1000 0000

现在明确了吧。

所以, 8 位有符号的整数取值范围的补码表示 1000 0000 到 0000 0000, 再到 0111 1111 即 -128 到 0, 再到 127 最终 -128 ~ +127。