一、引言
cpp
struct stu1
{
char a;
short b;
int c;
};
struct stu2
{
char a;
int c;
short b;
};
int main()
{
//输出结构体所占字节大小
printf("%d\n", sizeof(struct stu1)); // 结果:8
printf("%d\n", sizeof(struct stu2)); // 结果:12
}
在 C 语言中定义结构体时,成员变量顺序不同,最终结构体占用的内存大小也不同 ,并非简单把所有成员字节数相加。这背后就是结构体内存对齐机制。
二、内存对齐核心思想
(一)为什么要内存对齐
计算机CPU访问内存数据时,不会零散逐字节读取,而是优先以2的整数倍字节批量访问,常见为2Byte、4Byte、8Byte,以此提升读写效率。
内存对齐是为了让每一个成员的内存尽可能保持对齐,这样CPU一次访问的字节数,就可以直接完整取到这个元素。
核心思想:用空间换取访问时间效率
(二)内存对齐规则
1.第一个成员在与结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
(1)对齐数 = 编译器默认对齐数与该成员大小的较小值
(2)VS环境下默认对齐数是8
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4.如果是嵌套结构体
(1)嵌套的结构体对齐到自己的最大对齐数的整数倍处
(2)结构体整体大小就是"所有最大对齐数(含嵌套的对齐数)"的整数倍
cpp
struct stu1
{
char a; // 偏移 0,占用 1 字节 -> 【0】
// 偏移 1,"浪费 1 字节"(为了对齐)
short b; // 对齐数:min(2, 8) = 2
// 从偏移 2 开始,占用 2 字节 -> 【2, 3】
int c; // 对齐数:min(4, 8) = 4
// 从偏移 4 开始,占用 4 字节 -> 【4, 5, 6, 7】
};
// 总大小:8 Byte
// 校验:8 % 最大对齐数(4) == 0,满足规则!
cpp
struct stu2
{
char a; // 偏移 0,占用1字节 【0】
// 偏移 1、2、3,浪费3字节(对齐填充)
int c; // 对齐数:min(4, 8) = 4
// 偏移 4 开始,占用4字节 【4,5,6,7】
short b; // 对齐数:min(2, 8) = 2
// 偏移 8 开始,占用2字节 【8,9】
};
// 当前总长度:10 Byte
// 校验:10 % 最大对齐数(4) != 0,不满足规则!
// 自动填充字节,补齐到 12 Byte
(三)手动修改默认对齐数
cpp
#pragma pack(n) // 设置默认对齐数为 n(n 只能是 1、2、4、8、16)
#pragma pack() // 取消手动设置,恢复编译器默认(VS 默认 8)