数据表示
数据表示
补码的表示范围
假设机器字长为 n 位,补码可表示的数值范围:
| 字长 | 范围 | 举例 |
|---|---|---|
| 8 位 | ~ | int8_t |
| 16 位 | ~ | int16_t |
| 32 位 | ~ | int |
| 64 位 | ~ | long long |
不对称的原因:补码中负数比正数多一个(没有 −0),最小负数的绝对值比最大正数大 1。
移码
为什么引入移码?
浮点数的指数(阶码)可正可负。如果用补码表示指数,比较浮点数大小时会出问题。
比如两个正浮点数,指数分别是 +2 和 -3:
- 补码:
+2=00000010,-3=11111101 - 用无符号比较,
11111101反而 >00000010,比较器会认为指数-3比+2大 ✗
移码的思路:把整个指数范围往上”平移”一个固定值(偏置量),让所有存储的指数都变成非负数。这样用无符号整数比较就能正确判断浮点数大小,硬件比较器大大简化。
一句话:移码把有符号指数映射到无符号范围,让硬件用同一套比较电路就能比较浮点数。
计算公式
移码 = 真值 + 偏置值
| 精度 | 指数位数 | 偏置值 | 公式 |
|---|---|---|---|
| 单精度 (float) | 8 位 | 127 (2⁷−1) | 移码 = 真值 + 127 |
| 双精度 (double) | 11 位 | 1023 (2¹⁰−1) | 移码 = 真值 + 1023 |
通式:偏置值 = 2ⁿ⁻¹ − 1(n 为指数位数)
举例
单精度下,真值指数 = -3:
- 移码 =
-3 + 127 = 124 - 二进制:
01111100
真值指数 = +2:
- 移码 =
2 + 127 = 129 - 二进制:
10000001
现在无符号比较:129 > 124 ✓,正确反映了指数大小关系。
移码的本质
移码的核心思想:把真值整体向上平移 ,使所有值变成非负,从而能用无符号比较器做大小判断。
真值范围: -2^(n-1) ──────── 0 ──────── 2^(n-1)-1 │ │ │ ▼ +2^(n-1) ▼ +2^(n-1) ▼ +2^(n-1)移码范围: 0 ──────── 2^(n-1) ──────── 2^n-1| 项目 | 说明 |
|---|---|
| 偏置值的设置 | 机器字长为 n 时,偏置值 = |
| 真值最小值 | → 移码 = |
| 真值最大值 | → 移码 = |
移码是 IEEE 754 浮点数的基础,详见 浮点数和 IEEE 754。
数据的宽度和存储
常见的数据类型与宽度
C 语言中基本数据类型的典型宽度(以 32/64 位通用平台为准):
| 类型 | char | short | int | float | double |
|---|---|---|---|---|---|
| 字节数 | 1 B | 2 B | 4 B | 4 B | 8 B |
| 位数 | 8 bit | 16 bit | 32 bit | 32 bit | 64 bit |
unsigned仅表示无符号,不改变数据宽度——宽度由后面的类型决定。例如unsigned int仍然是 4 字节。
各种”字长”
1. 机器字长(CPU 字长)
最核心的概念。指 CPU 一次能处理的二进制位数,等于通用寄存器、ALU、数据总线的宽度。
- 常说的”32 位 CPU""64 位 CPU”就是指机器字长
- 机器字长越长,单次运算能处理的数据越大,寻址范围也越大
2. 存储字长
一个存储单元中存放的二进制位数。通常与机器字长相等,但不一定。
- 存储字长 = 机器字长 → 一个存取周期就能读写一个完整的机器字
- 主存常按字节编址(每个地址对应 8 位),但一次读出可能是 32 或 64 位
3. 指令字长
一条指令的二进制位数。
- 定长指令字:所有指令长度相同(如 MIPS 固定 32 位)
- 变长指令字:不同指令长度不同(如 x86,指令从 1 字节到 15 字节)
- 指令字长可以是机器字长的整数倍,也可以不是
4. 数据字长
数据总线上一次传输的二进制位数,通常等于机器字长。
总结对比
| 名称 | 含义 | 典型值 (64位机) |
|---|---|---|
| 机器字长 | CPU一次处理的位数 | 64 bit |
| 存储字长 | 存储单元存放的位数 | 64 bit(常对齐) |
| 指令字长 | 一条指令的位数 | 不定(x86变长) |
| 数据字长 | 数据总线一次传的位数 | 64 bit |
关键区别:机器字长是 CPU 决定的”能力上限”;指令字长取决于指令集设计,可以和机器字长不同;存储字长取决于存储器设计。
字节顺序(端序)
多字节数据在内存中的存放顺序有两种策略。以 int x = 12345678H(占 4 字节)为例:
大端存储(Big-Endian)
数据高位放在地址低位,数据低位放在地址高位。
| 地址 | 0800H | 0801H | 0802H | 0803H |
|---|---|---|---|---|
| 数据 | 12H | 34H | 56H | 78H |
- 最高字节
12H在最低地址 → 符合人类读写习惯 - 网络字节序(TCP/IP)采用大端
小端存储(Little-Endian)
数据高位放在地址高位,数据低位放在地址低位。
| 地址 | 0800H | 0801H | 0802H | 0803H |
|---|---|---|---|---|
| 数据 | 78H | 56H | 34H | 12H |
- 最低字节
78H在最低地址 → 便于 CPU 做不同宽度的类型转换 - x86 / ARM(默认)采用小端
关键:字节序只影响字节之间的排列,一个编址单位(1 字节)内部的 bit 顺序不受影响。
78H无论在哪个地址,其内部 bit 排列不变。



