80x86汇编与C语言:结构的存储
看懂 struct 字段偏移、对齐填充与汇编级访问方式
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
80x86汇编与C语言:结构的存储
看懂 struct 字段偏移、对齐填充与汇编级访问方式
为什么需要结构体
上一页我们看到结构体在内存里连续排列、各成员有偏移。那为什么要这样'绑'在一起?回到一个没有结构体的世界。
袋子里装不同类型的纸(学号、成绩),作为一个整体存放和传递
结构体在内存中的样子
上一节我们说结构体把多个变量打包存放——但打包不是简单堆叠,编译器要按每个字段的'脾气'摆位置。下面看一个具体例子,它在内存里到底长什么样。
大件放定位置,小件紧挨填缝,整箱尺寸按最大件对齐
结构体内存布局全景图
自左向右是低地址到高地址;蓝格是字段,橙格是编译器为对齐插入的填充。
字段顺序与内存排列
前页看到结构体在内存中是一块连续的字节,但悬着一个问题:字段到底是怎么排进去的?是按我写的顺序吗?
先到的坐前排,编译器不重排,内存顺序就是书写顺序
什么是内存对齐
前页看到字段顺序会影响结构体轮廓;那些空隙不是随意出现的,而是数据必须从合法边界开始留下的代价。
数据像车辆,地址是停入位置;车位线间距对应类型对齐,缝隙对应填充字节
对齐的基本规则
上一节我们明白了为什么要对齐。这一节落到具体规则——不同字节数的数据,分别要求地址是几的倍数。记住这几条,是读懂 struct 内存布局的钥匙。
小瓶 1 格随便摆;大瓶占 4 格只能从 1、5、9 格开始,绝不能骑在格子上
编译器处理对齐的步骤
编译器把源码中的struct一步步翻译成内存布局与机器码。
对齐规则代码验证
用 offsetof 和 sizeof 亲眼看编译器塞了多少填充字节。
原顺序 24 字节含 10 字节填充,重排后只剩 2 字节填充,省了 8 字节。
嵌套结构的对齐
前面我们掌握了「对齐值 = 内部成员对齐值的最大值」。当一个结构体的字段本身又是一个结构体时,这条规则还成立吗?这就是嵌套对齐要回答的问题。
每一层娃娃都有自己的最小卡位;外层间距要按所有层中最大的卡位来排
#pragma pack指令
用一段真实可编译的 C 代码,展示 #pragma pack(1) 如何把结构体压缩到 1 字节对齐,并对比默认布局的差异。
#pragma pack(1) 把对齐系数压成 1,int、double 紧贴前字段;sizeof 从默认 24 缩到 14,但未对齐访问会变慢。
自然对齐 vs 指定对齐
自然对齐跑得快却费内存,指定对齐紧凑却有性能代价——什么时候该牺牲什么?
- 对齐值 = 字段类型大小(int→4, double→8)
- 字段按自身大小对齐,padding 随声明顺序
- CPU 单条指令读出,缓存行友好
- 结构体总大小向最大字段对齐,有尾 padding
- 对齐值 = min(pack n, 字段类型大小)
- 强制紧贴排列,节省存储与 I/O 带宽
- n < 字段原始对齐 → unaligned 访问,性能下降
- 用于硬性兼容:协议头、固件、跨平台 ABI
跨平台对齐差异
自然对齐 vs 指定对齐,那是编译器层面的承诺。但硬件认不认账?x86、ARM、ARM64 三种 CPU 的回答完全不同——x86 睁一只眼闭一只眼,ARM64 可要较真。
x86 像美国,乱开能到但被抓罚款;ARM64 像英国,越线直接撞车(崩溃)
结构体数组的内存布局
一个结构体变量在内存中的样子——字段顺序、padding、对齐起点——我们都已经看清。那 `Student s[30]` 这 30 份数据,又是按什么规则在内存里排开的?
最大车型定车位宽;车位首尾相连;找第 i 个车位 = 入口 + i × 车位宽
结构体数组内存图示
横轴为内存地址递增方向。每个结构体占16字节,字段按对齐规则排列,尾填充让下一元素从对齐地址开始。
结构体数组的汇编视角
看 gcc 把 arr[i].y 翻译成什么:基址 + i×sizeof + 字段偏移。
汇编把 arr[i].y 拆成三步:基址 + i×sizeof(Point) + 字段偏移 4。sizeof 和 offsetof 都被编译器烧死成常数 8 和 4。
数据结构存储要点回顾
- ✓字段声明顺序直接决定 padding 数量
- ✓对齐是 CPU 访问单元带来的物理代价
- ✓#pragma pack 用对齐换紧凑,有性能成本
- ✓结构体数组按 sizeof 紧密排布,无指针数组空隙
结构体存储自测
在 32 位系统自然对齐下,struct { char a; int b; char c; } 占多少字节?
课后思考
先自己想,再看参考答案。三题分别从回顾、应用、迁移三个层次出发。
参考答案顺序决定了填充字节的位置和数量。同类型字段交换不改变总大小;不同类型交换可能减少或增加填充,是结构体压缩的切入点。
参考答案成员不再对齐到自然边界,CPU 可能需要多次访存才能拼出一个字。对齐换性能,pack 换兼容性,本质是空间与效率的权衡。
参考答案不一定。纯 int/char 成员时常见平台一致;含指针时 64 位指针占 8 字节,整体大小会变。课后可用 sizeof 在自己机器上验证。