跳到主要内容
🔍
0.1.3已发布beginner · 约 2 课时 · P0

原码/反码/补码与溢出

理解补码是负数的表示方式与"加负即减"的统一运算,能判断有符号溢出

  • 来源

标记说明:【来源】来自上传资料 · 【补充】课程新编 · 【纠错】按勘误表修正 · 【更新】过时内容已现代化 · 【待确认】无法可靠还原

完成标准(本章)

  • 📖 已阅读:滚动 ≥ 80% 且有效阅读 ≥ 150
  • ✏️ 已练习:小练习正确率 ≥ 60%
  • 📝 已通过测验:分数 ≥ 60
  • 🛠️ 已掌握还需完成实践任务
学习状态:未开始

0.1.3 原码/反码/补码与溢出

本章来源:补码与溢出概念来自《第一阶段讲义》11.4/11.5 节【来源】,重新组织表述;通俗解释与全部练习为新编【补充】。本章为手算章节,无代码示例。平台适用性 universal。

① 学习目标

  1. 分别写出一个负数的原码、反码、补码(8 位);
  2. 解释补码的两个好处:0 唯一、"减法变加法";
  3. 说出 8 位与 16 位有符号数的表示范围及其由来;
  4. 用"同号相加得异号"判断有符号加法溢出;
  5. 完成 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 位有符号数的取值范围是?(单选)

    ◌ 未作答

⑨ 章节测验

章节测验

5 题题库 · 随机抽 5 题 · 及格线 60 分 · 前端判分(学习自测)
开始测验 →

⑩ 实战任务

实践任务

手算 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)来源正文重新组织表述,未大段复制原文
通俗解释(钟表拨针类比)、练习/测验/任务补充全部新编