跳到主要内容

二进制补码到底怎么算:取反加一与符号位说清楚

用 -5 的 8 位补码这个例子,把补码的取反加一推导、为什么用补码统一加减、只有一个零,以及位宽和溢出讲到能上手,看完能自己手算也能反读寄存器值。

发布于 作者 李雷
#补码 #二进制补码 #有符号整数 #位运算 #计算机基础

二进制补码到底怎么算:取反加一与符号位说清楚

学到有符号整数的时候,很多人卡在一个地方:负数在内存里到底长什么样。十进制 -5 写出来是 -5,可寄存器里没有那个减号,只有一串 0 和 1。补码(two's complement)就是回答这个问题的方案,而且是几乎所有现代 CPU 实际采用的那一个。

一个例子先把流程跑通

先看结论再讲为什么。-5 在 8 位下的补码是 11111011。三步推导是这样的:

  1. 取绝对值 5,按 8 位补齐写成二进制:00000101,这一步叫原码。
  2. 逐位取反,0 变 1,1 变 0:11111010,这一步叫反码(one's complement)。
  3. 再加一:11111010 + 1 = 11111011,这就是补码,十六进制是 0xFB。

记住口诀就是「取反加一」。这里最容易翻车的是第三步:很多人取反到 11111010 就停了,但那串其实是 -6 不是 -5。漏掉加一,是手算补码时最常见的差一错误。你可以在 /zh/t/twos-complement-converter/ 里把 -5 填进去选 8 位,工具会把这三行原原本本列出来,跟你手算的每一步对一遍。

为什么最高位是符号,却不能单独看

补码的最高位看起来像符号位,1 表示负、0 表示正。但它不是单纯的标记,它是带权重参与运算的。8 位补码里最高位的权重是 -2^7 = -128,其余七位还是正常的正权重。所以 11111011 算出来是 -128 + 64 + 32 + 16 + 8 + 2 + 1 = -5,跟上面的取反加一结果一致。

这也解释了一个反复让人困惑的现象:11111111 在 8 位下是 -1,不带位宽却是 255。同一串数字,离开了位宽就没有有符号的含义。所以反向读取,也就是二进制转十进制那一侧,必须先把位宽定下来,否则这道题根本没有唯一答案。-1 在 8 位是 11111111,在 16 位是 1111111111111111,而无符号的 255 是另一个问题。

为什么偏偏选补码

历史上出现过三种表示有符号数的方案,对比着看就明白补码赢在哪。

原码用最高位单纯当符号标记,剩下的位表示数值大小。问题是它有两个零:00000000 是 +0,10000000 是 -0,加法器还得对符号做特殊判断。反码对负数逐位取反,同样躲不开两个零。

补码取反再加一,正好把那个多余的负零吃掉了,于是零只有一个表示 00000000。更关键的是:一个普通的加法器电路,不用区分符号,就能同时算对有符号和无符号的加减。做减法直接转成加它的补码即可,硬件因此省掉了一整套专用减法逻辑。统一加减、只有一个零,这两条就是补码能成为工业标准的根本原因。

我自己第一次真正理解这点,是在调一段定点数累加的固件时。当时把一个负的增量直接当无符号加进累加器,结果数值不降反升,盯着十六进制看了半天才反应过来:补码的妙处恰恰是我不需要特殊处理,按无符号加法照样得到正确的有符号结果,是我自己多此一举地拦了一道。

位宽与溢出:范围不是对称的

一个有符号的 n 位补码整数,范围是 -2^(n-1) 到 2^(n-1)-1。注意两端不对称:8 位能下到 -128,却只能上到 127。原因还是那个被吃掉的负零,零占了正数那一侧的一个槽位,于是负数能多伸出去一格。

| 位宽 | 最小值 | 最大值 | | --- | --- | --- | | 8 位 | -128 | 127 | | 16 位 | -32768 | 32767 | | 32 位 | -2147483648 | 2147483647 |

定结构体字段或寄存器大小的时候,这个范围必须心里有数。温度读数可能到 -40,int8 装得下,是 11011000;可一旦最坏情况冲到 -200,就塞不进 8 位了,得换 int16。等到生产环境最冷那天才发现 int8 撑溢出,代价比在这里拦下来大得多。所以遇到超界,好的工具会直接报错告诉你范围,而不是悄悄回绕给你一串误导的位串。

理解了补码,你会发现它跟其他进制转换是一脉相承的。无符号的进制互转、字节排布这些基础,可以顺手在 /zh/t/base-converter/ 里练熟,再回头看补码就只是在无符号二进制上多加了一层符号位的解释。

小结

补码三句话就能记住:取反加一得到负数表示,最高位带 -2^(n-1) 的权重,范围 -2^(n-1) 到 2^(n-1)-1 且负侧多一格。把这几条和手算流程对齐,无论是核对作业还是反读调试器里的寄存器值,都能算得稳、读得准。


Made by Toolora · Updated 2026-06-13