原码、反码、补码知识点总结

本文重新总结原码、反码、补码的含义与作用。原码、反码、补码是机器中数字的三种表示形式,补码解决了机器数计算中0表示歧义等问题,且能多表示一个数字。还探讨了C语言中int的最大最小值的十六进制表示,对负数存储形式给出不同解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好久没接触这三个熟悉而陌生的概念,以前也没理解透彻这三个概念的真正含义与作用,现在来重新做一个清晰而简单的总结。

首先,原码、反码、补码只是机器中对于数字的三种不同的表示形式。下面说的数都默认为整数,关于小数的表示方法在本文中不做探讨。

机器数与真值

在机器中,往往以二进制来表示数字,这个数叫做机器数。为了区分正数和负数,则需要加入一位符号位来表示正负,而符号位便是第一位,其中0表示正数,1表示负数。

+1= [0000 0001]
-1= [1000 0000]
+3=[0000 0011]
-3=[1000 0011]

在上面用8位二进制表示的数中,真正用于表示数的,其实只有后面7位。因此机器数的形式值(如1000 0011=2^7 + 2^1 + 2^0=131)不等于机器数的真值(如1000 0011=-000 0011=-2^1+2^0=-3)。
即带符号位的机器数对应的真正的数值才被称为机器数的真值。

原码、反码、补码

可以看到,如果机器采用机器数进行计算,那么会存在两个明显的问题。其一,是0的表示存在歧义,即存在+0和-0两种表示方法;其二,是同一个数没法通过按位相加得到0,如(+1) + (-1) = [0000 0001] + [1000 0001] = [1000 0010]=-2。基于以上两个显著问题,提出了使用原码、反码、补码的思想。

原码

原码可以简单理解为上面所说的机器码,即一个符号位加上真值的绝对值。

+1= [0000 0001]
-1= [1000 0000]
+3=[0000 0011]
-3=[1000 0011]

反码

对于正数而言,原码=反码
对于负数而言,反码为保持符号位不变,其余位按位取反。
显然,反码的反码=原码

+3=[0000 0011]=[0000 0011]-3=[1000 0011]=[1111 1100]

从下式可以看出,反码已经能使正负数进行正确的加法运算了,然鹅±0的情况依然存在。

(+3) + (-3) = [0000 0011]+ [1000 0011]= [0000 0011]+ [1111 1100]= [1111 1111]= [1000 0000]= -0

因此,为了解决±0的问题,需要引入补码。

补码

对于正数而言,原码=反码=补码
对于负数而言,补码=反码在最后一位加1
补码的补码=原码

+3=[0000 0011]=[0000 0011]=[0000 0011]-3=[1000 0011]=[1111 1100]=[1111 1101]

在补码中,只会存在一个0的表示,即[0000 0000]补,即

(+3) + (-3) = [0000 0011]+ [1000 0011]= [0000 0011]+[1111 1101]= [0000 0000]= [0000 0000]= 0

因此补码很好地解决了上述两个问题。同时,由于补码中不存在-0的表示,即[1000 0000],因此为了充分利用存储资源,[1000 0000]补成为了原码和反码中都不存在的一个值,即同样长度的表示中,补码比原码和反码能多表示一个数字。该数字的计算方式有点特殊,可以脑补给它转成原码时添加一位符号位以避免内存溢出(只是这么理解,实际并不会这样),将其进行求补运算以计算其原码,过程如下:

[1000 0000]=[1 1000 0000](脑补加一位) = [1 0111 1111]= [1 1000 0000]= -[1000 0000]= -256 

需要特别注意的是,上面1000 0000的原码和补码是相同的。

而同样用8位表示的正数,最大值为:

[0111 1111]= 255

因此使用补码后,负数会比正数多表示一个数。

C语言中int的最大最小值的十六进制表示

在理解清楚原码、反码、补码的基本知识后,可以看看C语言中的int的表示范围:

maxint = 0x7fffffff;
minint = 0x80000000;

首先要说明的是,在C语言中,或者说在内存中,十六进制的负数是以原码的形式保存的,而十进制的数字是以负数的形式保存的。
其中,maxint的表示为首位为0,其余全1,这是最大正数。
然而如果说十六进制的负数是原码存储,那么minint的表示为首位为1,其余全0,也就是前面所说的多出来的一位,即最小值-2147483648。
然鹅细心一点就会提出疑惑,0x8000 0001并不是-1,而是-2147483647。这么看起来似乎保存的不像是原码,更像是补码,毕竟它的补码是0xfffffffe,而这个用二进制的计算方法计算其十进制就可以得到-2147483647了。所以可以理解成这也是存储为补码。
不过网上更广泛的解释是,0x8000 0001是对0x8000 0000加1,所以是-2147483647。两种解释见仁见智,但结果都是一样的。


参考资料

  1. 原码,补码和反码
  2. 关于0x80000000为什么等于-2147483648和负数在内存上储存的问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值