来源:腾讯云开发者文章:https://cloud.tencent.com/developer/article/2403719
一、基础概念
sizeof(结构体)计算结构体占用内存字节数。 结构体总大小不等于所有成员字节简单相加,编译器会自动填充空洞(padding),结构体成员排列顺序会直接影响最终大小。
示例:
// 大小:12字节
struct stu{
char ch1;
int i;
char ch2;
};
// 调换成员顺序后,大小:8字节
struct stu{
char ch1;
char ch2;
int i;
};
二、内存对齐四条规则
对齐数:取「编译器默认对齐数」和「该成员自身大小」中较小的值
第一个成员变量,在结构体中偏移为 0;
其余成员的起始地址,必须是自身对齐数的整数倍;不满足则编译器自动填充 padding 字节;
结构体整体总大小,必须是该结构体最大对齐数的整数倍;末尾不足会补充 padding;
结构体嵌套:嵌套的子结构体,对齐到子结构体自身最大对齐数的整数倍;整个结构体总大小取全部成员最大对齐数的整数倍。
数组成员处理
数组不把整个数组当作一个单元。 数组整体对齐要求等于数组元素类型的对齐要求;数组内部元素紧密连续,内部不会插入 padding。
三、为什么要内存对齐
硬件限制:部分 CPU 不支持任意地址访问多字节类型,不对齐会触发硬件异常;
访问性能:对齐时 CPU 一次内存读取即可拿到数据;不对齐需要读两次内存再拼接,性能下降。

代价:牺牲少量内存(padding 空洞)换取安全性与访问速度。
四、修改对齐数:#pragma pack
可以手动指定最大对齐数,改变结构体内存布局,多用于二进制协议场景。
#pragma pack(n)设置对齐上限为 n 字节#pragma pack(1)关闭内存对齐,无 padding,结构体大小等于成员字节总和
示例:
#pragma pack(1)
struct Test{
char a;
int b;
};
#pragma pack() // 恢复默认对齐
注意:裸写 pack 不恢复,会污染后续所有结构体定义;工程中推荐使用
#pragma pack(push, n)/#pragma pack(pop)成对保存恢复对齐配置。
五、编码实践建议
将占用字节大的成员放在一起排布,可以减少 padding 填充,降低结构体内存占用。
补充说明(笔记附加)
VS 默认 pack 值为 8;GCC/Linux 遵循类型自然对齐,没有这个默认 pack 配置,两套环境行为不完全一样。
#pragma pack属于编译器扩展,不是 C 语言标准。实际工程中可以使用标准宏
offsetof(结构体类型,成员)获取成员偏移,不需要全部手算。