原码/反码/补码与溢出
理解补码是负数的表示方式与"加负即减"的统一运算,能判断有符号溢出
- 来源
标记说明:【来源】来自上传资料 · 【补充】课程新编 · 【纠错】按勘误表修正 · 【更新】过时内容已现代化 · 【待确认】无法可靠还原
完成标准(本章)
- 📖 已阅读:滚动 ≥ 80% 且有效阅读 ≥ 150 秒
- ✏️ 已练习:小练习正确率 ≥ 60%
- 📝 已通过测验:分数 ≥ 60 分
- 🛠️ 已掌握还需完成实践任务
0.1.3 原码/反码/补码与溢出
本章来源:补码与溢出概念来自《第一阶段讲义》11.4/11.5 节【来源】,重新组织表述;通俗解释与全部练习为新编【补充】。本章为手算章节,无代码示例。平台适用性 universal。
① 学习目标
- 分别写出一个负数的原码、反码、补码(8 位);
- 解释补码的两个好处:0 唯一、"减法变加法";
- 说出 8 位与 16 位有符号数的表示范围及其由来;
- 用"同号相加得异号"判断有符号加法溢出;
- 完成 10 道 8 位补码手算题(实践任务)。
② 前置知识
- 必修:0.1.2 进制与进制转换(位权、二进制与十六进制互转)。
③ 核心概念【来源】
| 概念 | 定义 |
|---|---|
| 原码 | 最高位作符号位(0 正 1 负),其余位为绝对值;有 +0/-0 两个零 |
| 反码 | 正数同原码;负数=原码除符号位外逐位取反;仍有 +0/-0 |
| 补码 | 正数同原码;负数=反码+1;0 唯一;8 位范围 -128~127 |
| 取反加一 | 负数的补码求法:正数补码 → 按位取反 → 加 1 |
| 进位(CF) | 无符号运算最高位向上进位,CPU 置进位标志 |
| 溢出(OF) | 有符号运算结果超出范围;判据:正+正得负、负+负得正 |
④ 通俗解释【补充】
把 8 位寄存器想象成一块只有 256 格的钟表表盘(0 到 255),指针每 +1 走一格、超过 255 回到 0:
- 原码/反码的问题:表盘上"0 点"有两格(+0 和 -0),而且想"倒退(减法)"还得另造一套往回拨的机构;
- 补码的妙处:把"往回拨 3 格"(-3)改写成"往前拨 253 格"——在 256 格的表盘上,253 和 -3 是同一格。于是减法全部变成加法,只需要一套往前拨的机构;
- 溢出:往前拨的格数太多,一圈 256 格装不下,"越过 12 点"的现象。所以正+正得负(拨过头绕回负数区)就是溢出的直觉解释;
- 这就是为什么 8 位有符号数范围是 -128~127:256 格里一半拨给负数(128 格),一半给正数与 0。
⑤ 示例代码
本章为手算章节,无代码示例。补码在 C 语言中的直接验证(如 char c = -1; printf("%x", (unsigned char)c))留到 1.2.2 数据类型一章结合类型转换讲解。
⑥ 编译与运行方法
本章无代码。
⑦ 常见错误
| 症状 | 原因 | 解决 |
|---|---|---|
| 把 0x80 说成 128(有符号) | 忘记补码解释 | int8_t 的 0x80 = -128;uint8_t 才是 128 |
| 异号相加判断成溢出 | 异号相加结果必在范围内 | 溢出只可能发生在同号相加 |
| 混淆进位与溢出 | 进位看无符号、溢出看有符号 | 先确定按有符号还是无符号解释 |
| 求 -128 的相反数又得 -128 | 补码 -128 没有对应正数 | 8 位补码正数最大 127 |
| 把 -1 的补码写成 1000 0001 | 用了原码表示 | 补码 -1 = 1111 1111 |
⑧ 小练习
小练习
学习自测:提交后才显示答案与解析(前端判分,不作为正式考试)ex-0-1-3-1.8 位补码中,-1 的二进制表示是?(单选)
◌ 未作答ex-0-1-3-2.填空:8 位补码 1000 0000 表示的十进制数是 ______。(填空)
◌ 未作答ex-0-1-3-3.8 位有符号数的取值范围是?(单选)
◌ 未作答
⑨ 章节测验
章节测验
⑩ 实战任务
实践任务
手算 8 位补码运算题集(10 道)并标注溢出
用手算完成 10 道 8 位补码加减运算,每题给出二进制演算过程、十进制结果与溢出判断, 达到"补码换算 30 秒一题、溢出判断零失误"。
输入与输出
无程序输入输出。交付物:10 道题的演算过程(二进制竖式 + 结果 + 溢出标志)。
功能要求
- 10 道题覆盖:正+正(含溢出 1 题)、负+负(含溢出 1 题)、正+负(3 题)、负+正(3 题)、特殊值(-1+1、-128+(-1))
- 每题写出:参与数补码 → 二进制加法竖式 → 结果补码 → 十进制解释 → 溢出判断与理由
限制条件
- 手算,不使用计算器
- 溢出判断必须说明依据(同号相加异号结果 / 超出范围)
验收步骤(自检清单 0/3)
验收标准
- 10 题全部正确(验收步骤 1)
- 溢出题判断正确且理由成立(验收步骤 2)
- 能解释 -128-1 溢出回绕到 +127 的补码机理(验收步骤 3)
常见失败原因
- 把进位标志(CF)与溢出标志(OF)混为一谈:进位看无符号、溢出看有符号
- 忘记 -128 没有对应正数(取反加一还是自己)
- 异号相加也判断溢出(异号相加不可能溢出)
可选扩展
- 把题集扩展到 16 位补码
- 预习 1.2.3:C 语言里 int 溢出是未定义行为还是回绕?(答案见后续章节)
完成必要清单后才能计入"已完成实践"(学习状态自动推导,不提供一键完成)
⑪ 面试问题
面试问题
计算机里负数为什么用补码而不是原码表示?高频C/C++ · easy
要点:补码让减法变成加法、且 0 只有一种表示;原码有两个 0 且减法电路复杂。
原码:符号位+绝对值,简单直观,但有两个 0(1000 0000 与 0000 0000),且加减法要区分符号, 电路复杂。反码解决了部分问题但仍有 +0/-0。补码:负数=正数取反加一,加法和减法共用一套电路, 0 唯一(全 0),且能多表示一个数(8 位是 -128)。这就是所有现代 CPU 采用补码的原因。
追问:- 追问:为什么 8 位补码范围是 -128~127 而不是 -127~127?
- 追问:0xFFFFFFFF 作为 int 是多少?(-1)
评分要点:- 0 唯一
- 减法统一为加法
- 多一个负数的范围说明
什么是溢出?有符号和无符号加法如何判断?高频C/C++ · medium
要点:结果超出表示范围即溢出;有符号看"同号相加得异号",无符号看进位标志。
溢出=运算结果超出该类型的表示范围。有符号加法判据:正+正得负、负+负得正(异号相加不可能溢出); 无符号看进位(最高位向上进位,CF=1)。硬件层面 CPU 同时给出进位标志与溢出标志, C 语言层面有符号溢出是未定义行为(编译器可能做激进优化),无符号回绕则是明确定义的。
追问:- 追问:为什么 C 语言有符号溢出是未定义行为?
- 追问:写代码如何避免溢出?(检查范围/用更大类型/编译器告警 -ftrapv)
评分要点:- 溢出定义
- 有符号判据
- 无符号进位
0x80 作为 int8_t 是多少?为什么?嵌入式 · easy
要点:-128。因为 1000 0000 是 8 位补码能表示的最小负数。
8 位补码范围 -128~127:1000 0000 按"取反加一"会回到自身,因此约定为 -128(这也是补码比 原码多一个负数的来源)。这个特值在嵌入式很常见:0x80 常作为"最小值/无效值"哨兵、I2C 等 协议中的标志位。回答时注意区分 int8_t(有符号)与 uint8_t(无符号,0x80=128)。
追问:- 追问:uint8_t 的 0x80 呢?(128)
评分要点:- 说出 -128
- 解释 1000 0000 特例
- 区分 int8_t/uint8_t
⑫ 延伸阅读
- 《深入理解计算机系统(CSAPP)》第 2 章:信息的表示与处理(2.2 整数表示、2.3 整数运算);
- C 标准(C11 §6.2.6.2 整数类型表示;可查 cppreference 的整型页面);
- 维基百科词条:Two's complement(查阅入口);
- 下一章预告:0.1.4 存储器层次与内存布局概念——补码表示的这些位,住在内存的哪个区域。
内容来源映射
| 内容部分 | 资料 | 位置 | 标记 | 说明 |
|---|---|---|---|---|
| 原码/反码/补码定义、补码运算、溢出与进位判断 | 第一阶段讲义 | 11.4/11.5 节(PAGE 179) | 【来源】 | 正文重新组织表述,未大段复制原文 |
| 通俗解释(钟表拨针类比)、练习/测验/任务 | 无 | 【补充】 | 全部新编 |