← 目录 / 第二章 · 变量与数据类型 / 2.3 原码、反码与补码

2.3 原码、反码与补码

计算机只认识 0 和 1,那它是如何表示负数的?科学家们为此设计了三种编码方案,依次改进,最终解决了这个问题。

原码、反码与补码

计算机只认识 0 和 1,那它是如何表示负数的?科学家们为此设计了三种编码方案,依次改进,最终解决了这个问题。

符号位约定:最高位(最左边)表示正负,0 代表正数,1 代表负数,其余位存储数值。以 8 位(1 字节)为例:

符号位示例
10 0000101 → +5(符号位为 0,表示正数)
21 0000101 → -5(符号位为 1,表示负数)

2.3.1 三种编码方案

1
原码
最直觉的写法:符号位表示正负,其余位直接写数字的二进制。
+5 → 0 0000101
-5 → 1 0000101
✗ 问题:加减法需要专门区分正负处理,电路复杂。
2
反码
规则:正数不变;负数符号位不变,其余位全部取反。
-5 原码:1 0000101
-5 反码:1 1111010
△ 问题:0 有两种表示(+0 和 -0),需额外处理。
3
补码 ✓
规则:正数不变;负数 = 反码 + 1。现代计算机真正使用的方案。
-5 反码:1 1111010
-5 补码:1 1111011
✓ -0 被消灭,多出的编码用来表示 -128!

2.3.2 验证:5 + (−5) 在三种编码下的结果

二进制加法演示
── 原码(错误)──────────────────
0 0000101 (+5)
+ 1 0000101 (-5)
──────────
1 0001010 = -10,完全不对!✗
── 反码(接近但有瑕疵)───────────
0 0000101 (+5 的反码)
+ 1 1111010 (-5 的反码)
──────────
1 1111111 = -0,还是不对 △
── 补码(正确!)────────────────
0 0000101 (+5 的补码)
+ 1 1111011 (-5 的补码)
──────────
1 0 0000000 最高位进位溢出,自动丢弃
0 0000000 = 0 完全正确!✓

2.3.3 三种编码对照表(8 位)

十进制 原码 反码 补码
+5 0000 0101 0000 0101 0000 0101
-5 1000 0101 1111 1010 1111 1011
+0 0000 0000 0000 0000 0000 0000
-0 1000 0000 1111 1111 (不存在!)
-128 无法表示 无法表示 1000 0000
-1 1000 0001 1111 1110 1111 1111
+127 0111 1111 0111 1111 0111 1111
📖
为什么 signed char 是 −128 到 127?补码消灭了 −0,空出来的编码 1000 0000 被用来表示 −128。8 位补码能表示 256 个数:−128~−1(128 个)加上 0~127(128 个),比原码多表示一个数。
📚
扩展阅读:C++20 标准正式强制要求有符号整数使用补码表示(此前是实现定义的)。补码不再是"可选方案",而是所有 C++ 平台的统一标准。理解三种编码的演进历史,有助于真正体会补码设计的精妙之处。