蔚淦丞
发布于 2026-09-18 / 0 阅读
0
0

结构体大小与内存对齐

来源:腾讯云开发者文章: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;
};

二、内存对齐四条规则

对齐数:取「编译器默认对齐数」和「该成员自身大小」中较小的值

  1. 第一个成员变量,在结构体中偏移为 0;

  2. 其余成员的起始地址,必须是自身对齐数的整数倍;不满足则编译器自动填充 padding 字节;

  3. 结构体整体总大小,必须是该结构体最大对齐数的整数倍;末尾不足会补充 padding;

  4. 结构体嵌套:嵌套的子结构体,对齐到子结构体自身最大对齐数的整数倍;整个结构体总大小取全部成员最大对齐数的整数倍。

数组成员处理

数组不把整个数组当作一个单元。 数组整体对齐要求等于数组元素类型的对齐要求;数组内部元素紧密连续,内部不会插入 padding。

三、为什么要内存对齐

  1. 硬件限制:部分 CPU 不支持任意地址访问多字节类型,不对齐会触发硬件异常;

  2. 访问性能:对齐时 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 填充,降低结构体内存占用。

补充说明(笔记附加)

  1. VS 默认 pack 值为 8;GCC/Linux 遵循类型自然对齐,没有这个默认 pack 配置,两套环境行为不完全一样。

  2. #pragma pack属于编译器扩展,不是 C 语言标准。

  3. 实际工程中可以使用标准宏 offsetof(结构体类型,成员) 获取成员偏移,不需要全部手算。


评论