在C语言中, signed char 类型的范围为-128~127,每本教科书上也这么写,但是没有哪一本书上(包括老师)也不会给你为什么是-128~127,这个问题貌似看起来也很简单容易, 以至于不用去思考为什么,但是为什么最小负数绝对值总比最大正数多1 ,这个问题甚至有的工作几年的程序员都模棱两可,因为没有深入思考过,只知道书上这么写。于是,我不得不深入思考一下这个被许多人忽视的问题。
原码、反码、补码
我们都知道计算机中数值一律用补码来表示(存储)。为什么不直接用原码的二进制存储呢?我们先来看一下这个问题:
大家都知道计算机内部是以二进制来存贮数值的,无符号整数会用全部为来存储,有符号的整数,最高位当做符号位 ,其余为表示数值,这样貌似合理, 却带来一个麻烦,当进行加法时,1+1如下:
0000 0001
+ 0000 0001
——————
0000 0010 ………………2
当相减时 1-1=? 由于计算机只会加法不会减法(计算机中没有减法 器,只有加法器),它会转化为1+(-1) ,因此
0000 0001
+ 1000 0001
——————
1000 0010 …………….-2
1-1= -2? 这显然是不对了,所以为了避免减法运算错误,计算机大神们发明出了反码,上面提到的二进制都是原码形式,
反码是原码除最高位其余位取反,规定:正数的反码和原码相同,负数的反码是原码除了符号位,其余为都取反,因此-1 的源码为 1 0000001 ,反码为 1 1111110, 现在再用反码来计算 1+(-1)
0000 0001
+ 11111 1110
——————
1111 1111 …………….转化为原码就是1000 0000 = -0;
虽然反码解决了相减的问题,却又带来一个问题,-0 ,既然0000 0000 表示 0,那么就没有 -0 的必要, 出现 +0= -0=0 ,一个0 就够了,为了避免两个0的问题,计算机大师们又发明了补码。
补码规定: 整数的补码是其本身,负数的补码为其反码加一 ,所以,负数转化为反码需两个步骤, 第一,先转化为反码,第二: 把反码加一。
再用补码计算 1+(-1):
0000 0001
+ 1111 1111
——————
1 0000 0000 ……这里变成了9位,由于char 为8位,最高位1 被丢弃 结果为0 ,运算正确。
再看,
-0 :原码 1000 0000 的补码为1 0000 0000 ,由于char 是 八位 ,所以取低八位00000000,
+0 :原码为0000 00000 ,补码为也为 0000 0000 ,
虽然补码0都是相同的,但是有两个0 ,既然有两个0 ,况且0既不是正数,也不是负数, 用原码为0000 0000 表示就行了, 这样一来,有符号的char ,原码都用来表示-127~127 之间的数了,唯独剩下原码1000 0000 没有用,现在再来探讨一下关于剩下的那个1000 0000。
-128的由来
既然 -127 ~0~ 127都有相应的原码与其对应,那么1000 0000 表示什么呢,当然是-128了,为什么是-128呢, 为什么能用它表示-128进行运算,如果不要限制为char 型(即不要限定是8位),-128的原码:1 1000 0000 ,9位,最高位符号位,再算它的反码:1 0111 1111,进而,补码为: 1 1000 0000,这是-128的补码,发现和原码一样, 但是在char 型中,是可以用1000 000 表示-128的,关键在于char 是8位,它把-128的最高位符号位1 丢弃了,截断后-128的原码为1000 000 和-0的原码相同,也就是说
1000 0000 和-128丢弃最高位后余下的8位相同,所以才可以用-0 表示-128,这样,当初剩余的-0(1000 0000),被拿来表示截断后的-128,因为即使截断后的-128和char 型范围的其他数(-127~127)运算也不会影响结果, 所以才敢这么表示-128。
比如 -128+(-1):
1000 0000——————丢弃最高位的-128
+ 1111 1111 —————– -1
——————
10111 1111 ——————char 取八位,这样结果不正确,不过没关系 ,结果-129本来就超出char型了,当然不能表示了。
比如 -128+127:
1000 0000
+ 0111 1111
——————
1111 1111 ————– -1 结果正确, 所以,这就是为什么能用 1000 0000表示-128的原因
当数据总线从内存中取出的是1000 000 ,CPU会给它再添最高一位,变为1 1000 0000 这样才能转化为 -128输出,不然1000 0000 如何输出?这当然是我的一种推断,具体怎么实现还得问CPU的设计者了。
在补码中 0-127 是从0x00-0x7F依次递增的;而-1到-128是从0xff-0x10依次递减的
本文转自https://blog.csdn.net/daiyutage/article/details/8575248。稍作修改。