二进制与补码
位模式本身只是 0/1;把它解释为无符号数、有符号补码、地址或指令,要看上下文和位宽。
一句话: 位模式本身只是 0/1;把它解释为无符号数、有符号补码、地址或指令,要看上下文和位宽。
本章导航#
位与进制 · 位运算 · 有符号数 · 溢出与扩展 · RISC-V 实例
学习目标#
- 在二进制、十进制之间转换。
- 计算补码表示、可表示范围和逻辑/算术移位结果。
- 区分位宽固定的硬件运算与高级语言的溢出规则。
1. 位、字节与进制#
一个 bit 是一个二进制位,只能为 0 或 1。一个 byte 通常为 8 bit。十进制数按 10 的幂展开,二进制按 2 的幂展开:
1101₂ = 1×2³ + 1×2² + 0×2¹ + 1×2⁰ = 13₁₀
十进制转二进制可反复除以 2 并倒序读取余数:13 → 余数 1、0、1、1 → 1101₂。
| 写法 | 精确含义 | 例子 |
|---|---|---|
| bit | 单个位 | 1 bit |
| byte / B | 8 位 | 1 B = 8 bit |
| kB / MB | SI 十进制单位 | 1 kB = 1000 B |
| KiB / MiB | IEC 二进制单位 | 1 KiB = 1024 B |
代码和旧教材常把 KB 写成 1024 B;严格书写时,建议用 KiB 表示 1024 B。
2. 位运算#
下表按单个位演示;多位运算逐位进行:
| A | B | A AND B | A OR B | A XOR B |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
1010& 1100= 1000
1010^ 1100= 0110NOT 会在指定位宽内翻转每一位。真实操作必须明确位宽:4 位的 NOT(1010) 是 0101,8 位则是 11110101。
3. 有符号数和补码#
无符号数#
n 位无符号数范围是 0 到 2ⁿ−1。8 位例子:00000000 = 0,11111111 = 255。
二进制补码#
常见 n 位有符号整数使用二进制补码,范围为 −2ⁿ⁻¹ 到 2ⁿ⁻¹−1。正数按普通二进制表示;负数可对其绝对值逐位取反再加 1。
以 8 位 −5 为例:
+5 00000101逐位取反 11111010加 1 11111011 ← −5 的 8 位补码可用权重法验证:最高位权重为 −2⁷,其他位权重依次为 2⁶…2⁰;11111011 = −128 + 64 + 32 + 16 + 8 + 0 + 2 + 1 = −5。
| 位宽 | 无符号范围 | 有符号补码范围 |
|---|---|---|
| 8 | 0…255 | −128…127 |
| 32 | 0…2³²−1 | −2³¹…2³¹−1 |
| 64 | 0…2⁶⁴−1 | −2⁶³…2⁶³−1 |
补码只有一个 0,并能让加法器用同一套位运算处理加法和减法。固定 n 位的运算结果可理解为对 2ⁿ 取模。
4. 溢出与扩展#
8 位补码中,127 + 1 的位运算结果为 10000000;将其解释成补码就是 −128。位模式得到结果与该结果是否超出有符号范围是两件事。
- 对补码加法,若两个操作数同号而结果异号,则发生有符号溢出。
- 无符号加法若超出位宽,则高位进位被截掉,相当于模 2ⁿ。
- C 语言的有符号整数溢出属于未定义行为;不要把某次硬件回绕结果当成 C 语言保证。
扩展位宽时要区分:
- 零扩展: 高位填 0,保持无符号数值。
- 符号扩展: 复制原最高位,保持补码数值。
移位也要区分:逻辑右移左侧补 0;算术右移通常复制符号位。左移在数学上像乘 2,但固定宽度下高位可能丢失,且语言层面的溢出规则可能不同。
5. RISC-V 中的位宽#
RISC-V 指令按寄存器宽度和指令语义操作位模式。RV32 的整数寄存器为 32 位,RV64 为 64 位。以 addi 为例,立即数是有限宽度且按规范符号扩展;它不是任意大的十进制常量。
RV64 的 lw 读取 32 位并符号扩展到 64 位;lwu 则零扩展。这个区别在读反汇编和调试数据时很重要。
自测: 8 位补码中 −1 是多少?答案是 11111111;符号扩展到 16 位后仍表示 −1:1111111111111111。
核心结论: 先问“几位、按什么类型解释”,再读二进制;位模式不是天然的正数或负数。
下一篇: 03 · RISC-V 寄存器 → 04 · RISC-V 指令详解