C语言结构体内存对齐问题

发布于:2025-06-14 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、内存对齐的基本原则

1、成员对齐规则

        每个成员的起始地址必须是其类型大小的整数倍(或指定对齐值的整数倍)

 例如:

  • char(1字节)可以放在任意地址
  • short(2字节)必须从偶地址开始(如0x0000、0x0002)
  • int(4字节)必须从4的倍数地址开始(如0x0000、0x0004)
  • double(8字节)必须从8的倍数地址开始

2、结构体整体对齐规则

结构体的总大小必须是最宽成员类型大小的整数倍(或指定对齐值的整数倍)

如果结构体包含嵌套结构体,嵌套结构体的对齐要求以内部结构体的最大对齐值为准

二、内存对齐示例

示例1:基础对齐
struct Example1 {
    char a;     // 1字节(地址0x0000)
    // 填充3字节(0x0001~0x0003)
    int b;      // 4字节(地址0x0004)
    // 总计:8字节(1 + 3 + 4)
};

原因:int需要3字节对齐,因此a后填充3字节,使b从地址4开始

总大小:sizeof(struct Example1) = 8

示例2:调整成员顺序
struct Example2 {
    int b;      // 4字节(地址0x0000)
    char a;     // 1字节(地址0x0004)
    // 填充3字节(0x0005~0x0007)
};

原因:调整顺序后,a后的填充减少,但结构体总大小仍需对齐到4字节的倍数

总大小:sizeof(struct Example2) = 8

示例3:嵌套结构体
struct Example3 {
    char a;         // 1字节(地址0x0000)
    // 填充3字节(0x0001~0x0003)
    struct Example1 inner;  // 最宽成员为int(4字节)
    // inner的起始地址为0x0004
};

原因:Example1结构体内的最大对齐值为int,即4字节

总大小:sizeof(struct Example3) = 12(1+3+8)

三、控制对齐方式

1、使用#pragma pack(n)指定对齐值

通过预编译指令#pragma pack(n)可以显式指定对齐方式:

#pragma pack(1)  // 禁用对齐填充
struct Packed {
    char a;
    int b;
};
#pragma pack()   // 恢复默认对齐
  • 结果:sizeof(struct Packed) = 5 (1 + 4)
  • 注意:此方式可能导致性能下降或硬件异常(如ARM平台不允许未对齐访问)

2、使用offsetof宏查看偏移量

标准库<stddef.h>中的offsetof(type, number)可以计算成员相对于结构体起始地址的偏移:

#include <stddef.h>
offsetof(struct Example1, b);  // 返回4

四、内存对齐的原因

1、硬件限制

  • 某些处理器(如ARM)不允许访问未对齐的内存地址,强行访问会出发硬件异常
  • x86/x64平台虽然支持未对齐内存访问,但效率较低

2、性能优化

  • 对齐的内存,访问时可以减少CPU访问次数(如读取4字节对齐的int只需要一次访问,未对齐可能需要两次)
  • 缓存行对齐可以减少缓存冲突


网站公告

今日签到

点亮在社区的每一天
去签到