第 5 课|3.3:数据格式
x86 的历史宽度名称
| x86 名称 | 位数 | 字节数 | 常见整数后缀 |
|---|---|---|---|
| byte | 8 | 1 | b |
| word | 16 | 2 | w |
| double word | 32 | 4 | l |
| quad word | 64 | 8 | q |
x86 起源于 16 位的 8086,因此word固定表示 16 位。处理器扩展到 32 位和 64 位后,旧名称仍被保留:32 位叫 double word,64 位叫 quad word。这里的word是 x86 历史术语,不应理解成“当前机器最自然的整数宽度”。
本书环境中的 C 类型大小
| C 类型 | 大小 | Figure 3.1 中的类型名称 | 汇编后缀 |
|---|---|---|---|
char | 1 字节 | Byte | b |
short | 2 字节 | Word | w |
int | 4 字节 | Double word | l |
long | 8 字节 | Quad word | q |
指针,例如char * | 8 字节 | Quad word | q |
float | 4 字节 | Single precision | s |
double | 8 字节 | Double precision | l |
这些大小针对教材采用的 x86-64 Linux/GCC 数据模型。尤其要注意:教材中的 Clong是 8 字节;Windows x64 通常把 Clong定义为 4 字节,所以 C 类型大小仍需结合 ABI 和平台判断。
整数指令后缀
b -> 1 字节 w -> 2 字节 l -> 4 字节 q -> 8 字节例如:
movb ... # 移动 1 字节 movw ... # 移动 2 字节 movl ... # 移动 4 字节 movq ... # 移动 8 字节movl中是小写字母l,不是数字1。它在整数指令中表示 32 位 double word,不能因为字母l就把它理解成 C 的long。
Figure 3.1 还把float记为后缀s、double记为后缀l。因此不能脱离指令系列,仅凭最后一个字母判断宽度:整数和浮点指令使用不同的指令系列及寄存器,完整指令与上下文可以消除歧义。
指针宽度与所指对象宽度
char*p;short*q;在本书环境中,p和q本身都是 8 字节地址;但解引用后的对象宽度不同:
p -> 8 字节指针 *p -> 1 字节 char q -> 8 字节指针 *q -> 2 字节 short因此,“复制指针本身”和“通过指针访问对象”是两种不同操作。前者按地址宽度处理;后者按所指对象的类型选择访问宽度。
例如%rax中保存char *p时,%rax保存的是 8 字节地址,但读取*p只访问%rax所指位置的 1 字节。若结果要放入更宽寄存器,编译器还会选择符号扩展或零扩展指令,这将在后续数据传送部分学习。
关于long double
x86 家族历史上还使用过 80 位扩展精度浮点格式,C 可用long double表示。教材提醒这种格式的平台可移植性和硬件性能特征与float、double不同,因此本章主要围绕 4 字节float和 8 字节double展开。
本节易错点
- 把 x86 的
word错当成 64 位;实际上它固定是 16 位。 - 把整数后缀
l错当成 Clong;整数语境中的l表示 4 字节。 - 认为所有平台的 C
long都是 8 字节;这取决于平台 ABI。 - 因为指针是 8 字节,就误以为通过指针总要访问 8 字节。
- 只看一个后缀字母,不结合完整指令、数据类型和寄存器类别判断。