先看一个例子:
为什么??c = (-100)+(-100的),打印出来的结果为56呢??
让我们探究整数的编码之旅吧!
一.各种概念各种定义···
1.无符号整数,例如unsigned char/int/short 就不介绍了。
2.有符号数 char/int的编码:
(1)原码:原码表示法是整数的一种简单表示法。符号位:0表示正号,1表示负。数值一般用二进制表示。
(2)反码:正数:其反码和原码相同。负数:其反码为原码各位取反而得到(但是符号位除外)。
(3)补码:正数:其补码和原码相同。负数:其反码为其反码的基础上末位加1;即:取反加1。
但是但是!为什么!为什么要设计原码反码补码?有啥子用?考试吗?(恩,大一的时候作为初学者,在考试时总会想这个问题,啊这是为什么这这样设计?)。
直到看到了下面这句话:
所有编码系统的设计,都在追求连续性和唯一性。原码、反码和补码的演化,就是在不断提高整数编码的这两个方面。
重点是:连续性!唯一性!
二.图形解读整数编码:
1.原码的二进制码与整数对用的关系图:
上图发现两个bug:
(1)存在重复0,分别0000 0000 和1000 0000
(2)存在两个间断点,分别为:
0111 1111 -> 1000 0000,即127突变为-0.
1111 1111 -> 0000 0000,即-127突变为+0.
这就涉及到整个整数范围内的数值连续性,任何的间断点都会导致溢出问题。所以间断点越少越好。
2.反码的二进制码与整数对用的关系图
观察图一图二,发现右边图形做了一次翻转,bug2的间断点被修复了,也就是说间断点从两个变成一个。
bug1:依旧存在重复0。
bug2:两个间断点减少到一个,不能再优化了。
3.补码的二进制码与整数对用的关系图
再观察,我们发现这一次右边图形向下移动1,于是最小负整数从-127变成-128.
char:一个字节 8位(1,2,3·····127,-128,-127,·····2,1,0,1,2循环下去···)
原码:最大值 0111 1111(0符号位表示正 十进制表示为127)如图一
最小值1111 1111(1符号位表示负 十进制数为-127)如图一
结合图示,也就是说,原码本来是有bug的,它不准确,所以计算机中不用原码来计算。
补码:最大值0111 1111(127)如图三
最小值10000 000(-128)如图三
这里我纠结了一下为什么补码1000 0000表示为-128而不是-0。说明还是有点懵啊。
因为它是补码,是补码!是补码!通过三张图也看的出来,补码是经过优化的,补码 = 原码取反+1(符号位除外。
1000 0000 :1表示负数,000 0000取反 111 1111 加1:1000 0000 这个表示128 ,再加上符号位表示的负数,最后结果:-128.
那么怎么计算补码所表示的那个值呢?(答案:取反加1包括符号位)
例如:补码1000 0001,求其表示的十进制值 分3步:
1.它是补码 所以1为符号位,十进制是一个负数。
2.取反后为0111 1110;再加1为0111 1111表示127
3.最后得结果:-127
总结:通过补码计算其表达的数值(十进制):取反,加1,包括符号位。
这里容易与通过原码得到补码混淆,“补码 = 原码取反加1,符号位除外”。所以我们再看一个例子:
-10(十进制),原码为:1000 1010(有负,第一位为1,10的二进制为1010),
补码为:1111 0110(原码取反加1 && 符号位除外)
通过补码算原本的值:1.它是补码并且第一位1,所以得出:负数。2.取反0000 1001,加1:0000 1010 3.得出:-10
所以,为什么要有补码,因为一开始只有原码,但是原码有bug,怎么办,那就优化一下(取了个反加了个1),然后给它起了个名字,叫:补码。
再通过下面例子观察原码反码补码的差别:
通过这个例子,我们发现,好神奇,只有补码没有计算错误。
最后,回到最初的问题,c = (-100)+(-100)
计算机中,存储有符号char以补码形式。
-100的原码为:1110 0100(第一位1表示负 110 0100表示100)
-100的补码为:1001 1100
两个(-100)相加,形式为两个补码相加:
1001 1100 + 1001 1100 = 0011 1000
补码0011 1000第一位为0,说明是正数,再算其值为:56。
--------------------------------------1年后更新---------------
居然又忘了这个原码反码补码,碰到一个笔试题:
int a = 0xffffffff;
printf("%d",a);
结果为多少呢?
分析:0xffffffff (十六进制),即11111111 11111111 11111111 11111111(二进制)
补码:11111111 11111111 11111111 11111111
计算机直接把他当做补码处理啊,所以他是-1.
我还以为11111111是原码,计算机先把11111111转化成补码,再得其值。