Lecture 14:知识 - 数据的对齐和大小端存放方式
Chinese-language Computer Science 408 note: Lecture 14:知识 - 数据的对齐和大小端存放方式. Original source available where applicable.
On this page
This note is currently available in Chinese. The original wording, formulas and diagrams are preserved to avoid an unverified technical translation.
描述:大小端回答“多字节数据的各字节怎样排在地址上”;对齐回答“一个对象从哪个地址开始”。二者都以字节编址为前提,但解决的是不同问题。
4.1 大端方式与小端方式
现代机器通常按字节编址:一个地址对应 1 B。多字节数据的最高有效字节(MSB)与最低有效字节(LSB)如何从低地址到高地址排列,构成端序。
| 方式 | 低地址存放 | 高地址存放 | 口诀 |
|---|---|---|---|
| 大端(big-endian) | MSB,高位字节 | LSB,低位字节 | 大端高存低 |
| 小端(little-endian) | LSB,低位字节 | MSB,高位字节 | 小端低存低 |
例:32 位数 0x01234567 从地址 0x0800 开始存放:
| 地址 | 0x0800 |
0x0801 |
0x0802 |
0x0803 |
|---|---|---|---|---|
| 大端 | 01 |
23 |
45 |
67 |
| 小端 | 67 |
45 |
23 |
01 |
- 大小端只改变字节之间的次序,不改变一个字节内部 8 位的位序。
- 读取内存转储中的多字节整数或指令内的多字节数值字段时,小端机器会把最低有效字节放在低地址,按通常的高位到低位数值写法还原时需反转这些字段的字节顺序;不能把整条变长机器指令的所有字节机械地整体倒序。大端数值字段的内存字节序与通常十六进制从高到低的书写顺序一致。
- 网络协议或文件格式可规定固定端序,因此跨平台传输多字节整数时可能需要显式进行字节序转换;不要以本机端序猜测外部数据格式。
4.2 数据对齐存储
4.2.1 对齐的含义和性能原因
若字长 32 位(4 B),按边界对齐时,数据起始地址应为其大小的整数倍:半字(2 B)地址为 2 的倍数,字(4 B)地址为 4 的倍数。一般规律是对象起始地址满足:
$$\text{address}\bmod\text{alignment}=0$$
- 对齐后,一个字节、半字或字通常可在一次合适宽度的访存中取到。
- 未对齐的半字/字可能跨越两个存储字或两个总线传输边界,硬件需两次读取并拼接高低字节,因而降低效率;某些体系结构还可能直接对未对齐访问报异常。
- 编译器会在成员之间填充 padding 字节使对象满足对齐要求。这会牺牲部分空间,换取更简单、快速的访存与 ABI 兼容。
4.2.2 结构体对齐
在本讲的常见规则下(具体 ABI 仍可能调整):
| 类型 | 常见对齐值 |
|---|---|
char |
1 B |
short |
2 B |
int |
4 B |
结构体布局规则:
- 每个成员的偏移地址须是其自身对齐值的整数倍;不满足就在前一个成员后补空字节。
- 结构体总长度须是所有成员中最大对齐值的整数倍;尾部不足也要补空字节。
例:在上述规则下,struct { char c; int x; short s; } 的偏移可为 c:0,为使 x 对齐先补 3 B,x:4,s:8;已用 10 B,最大对齐为 4,尾部再补 2 B,总大小为 12 B。
原 PDF 的 2012 年例题:机器按字节编址、小端存放,int 为 4 B、short 为 2 B,成员按其类型边界对齐。设结构体变量首地址为 0xC008:
struct {
int a;
char b;
short c;
} record;
record.a = 273;
求地址 0xC008 中的内容,以及 record.c 的地址。原题选项分别为 A 0x00, 0xC00D,B 0x00, 0xC00E,C 0x11, 0xC00D,D 0x11, 0xC00E。先把 $273$ 写成 32 位十六进制数 0x00000111;小端存放时,a 的四个字节依次为 11 01 00 00。
| 地址 | 内容或用途 |
|---|---|
0xC008 |
a 的最低有效字节 0x11 |
0xC009--0xC00B |
a 余下的三个字节:01 00 00 |
0xC00C |
b(题目未赋值,不推定其内容) |
0xC00D |
为使 short c 从 2 的倍数地址开始而填充的 1 B |
0xC00E--0xC00F |
c 占用的 2 B |
因此 0xC008 中是 0x11,record.c 的地址是 0xC00E,对应原题 D。填充字节及未初始化成员的值不参与推算。
题型:#端序与对齐
第一部分:解题步骤
- 端序题:先将数拆为每两位十六进制一个字节,列出“低地址到高地址”的表;大端按原序,小端反序。
- 对齐题:从偏移 0 开始逐成员放置,每放一个成员先向上取整到其对齐值的倍数;全部成员后再向上取整到最大对齐值倍数。
- 区分“对象值的字节序”和“结构体成员排列”:成员通常按声明顺序布置,对同一成员内部的多字节存放再适用大小端。
第二部分:易错点
- 大端不是“高地址存高位”,恰好相反:低地址放高位字节。
- 小端并非把二进制每一位倒过来,只交换字节顺序。
- 结构体大小不是成员大小直接相加;既可能在成员之间补齐,也可能在末尾补齐。
相关知识
- 科目导航:计算机组成原理导航
- 阅读顺序:上一篇:指令格式 · 下一篇:CISC 和 RISC
4.3 本节复盘
- 大端低地址放 MSB,小端低地址放 LSB;端序影响多字节对象的内存字节排列,不改变字节内部位序。
- 对齐要求起始地址为对齐值整数倍,目的是避免跨边界访存;未对齐可能需要两次访存和拼接。
char/short/int常按 1/2/4 B 对齐;结构体成员各自对齐,最终大小再对齐到最大成员对齐值。- 端序表要按低地址到高地址列,结构体题要逐成员上取整,不能只凭直觉相加。