C语言-补码

在计算机内,有符号数有3种表示法:
原码
原码就是符号位加上真值的绝对值,即用第一个二进制位表示符号(正数该位为0,负数该位为1),其余位表示值。
反码
正数的反码与其原码相同;
负数的反码是符号位不变其余原码逐位取反。
补码
正数的补码就是其本身;
负数的补码是在其反码的基础上+1
举例:
[+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补
[-1]= [1000 0001]原 = [1111 1110]反 = [1111 1111]补
计算机内,为何要使用补码
在计算机内,数据都是按照补码的形式存储的,且计算机没有减法器只有加法器,所以任何的减法都当作加法进行运算,如1-1=1+(-1)=0;
1 - 1 = 1 + (-1) = [0000 0001]补 + [1111 1111]补 = [0000 0000]补 = [0000 0000]原 = 0
补码的优点:
可将减法变为加法,省去减法器;
无符号数及带符号数的加法运算可以用同一电路完成;
使用补码,修复了原码中0的符号(有 [+0] [-0] 之分)以及存在两个编码(0000 0000 和 1000 0000)的问题,而且还能够多表示一个最低数。比如在在8位二进制中,使用原码/反码表示的范围为[-127,+127],包含 [+0] [-0] 一共256个;使用补码表示的范围为[-128,+127],0没有符号。
补码溢出
同号数相加得到的符号位和两加数符号位不同,既是溢出。
例如8bit的byte类型的表示范围为[-128,+127],那么+128、+129、-129、-130等超出范围的数该怎么表示呢?
+128 = 127 + 1 = [0111 1111]补 + [0000 0001]补 = [1000 0000]补 = -128
+129 = 127 + 2 = [0111 1111]补 + [0000 0010]补 = [1000 0001]补 = [1111 1111]原 = -127
-129 = -128 + (-1) = [1000 0000]补 + [1111 1111]补 = [0111 1111]补 = 127
-130 = -128 + (-2) = [1000 0000]补 + [1111 1110]补 = [0111 1110]补 = 126
上面是用补码的方式表示,还有一个简单的方法表示:
8bit表示范围[-128,+127],把这个范围看作是一个循环体,-128看作起点,+127看作终点,超过终点就回到起点重新开始,反之超过起点就回到终点,这样在做笔试题或者计算溢出时就不用去写补码就能直接算出溢出值。
总结得出:
超上限的数 x = x - 256;
超下限的数 x = x + 256;
下限的相反数与下限相等;
上限的相反数是上限直接取负值。
【C语言-补码】打印补码
%x打印出在计算机存储的补码形式(64位系统):
char a=-1;
printf("a=%d,%x\n",a,a); //a=-1,ffffffff
char a=128;
printf("a=%d,%x\n",a,a); //a=-128,ffffff80

    推荐阅读