.webp)
结构体内存对齐
本文最后更新于 2025-07-13,文章内容可能已经过时。
为什么存在内存对齐
1. 平台原因(移植原因)
不是所有的硬件都能任意访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出异常
2. 性能原因
数据结构(尤其是栈)应该尽可能的在自然边界上对齐,为了访问未对齐的内存,CPU 需要访问内存 2 次;访问对齐后的内存,CPU 只需要访问内存 1 次。
在 Windows 的 VS 中默认对齐值为 8
Linux 中(GCC 编译器)默认对齐值为 4
在内存中我们一般读取数据不是按内存来读取,一般都是按内存块来读取。
未对齐的情况下,当需要访问 int 类型的数据时,需要 CPU 访问 2 次内存块(内存块 1 和内存块 2)
对齐的情况下,当访问 int 类型的数据时,只需要 CPU 访问 1 次内存块(内存块 2)即可
是一种空间换时间的做法
结构体内存对齐规则
-
第一个成员在结构体变量偏移量为 0 的地址
-
有效对齐值为 Min(编译器默认对齐值,结构体中成员数据类型中占用内存最大值)
-
其他成员要对齐到 Min(有效对齐值,该成员数据类型的内存大小)的整数倍
-
⚠结构体总大小为有效对齐值的整数倍
-
如果嵌套结构体,有效对齐值为 Min(编译器默认对齐值,Max 嵌套结构体中成员数据类型中占用内存最大值,结构体中成员一数据类型占用内存、结构体中成员二数据类型占用内存……结构体中成员 N 数据类型占用内存嵌套结构体中成员数据类型中占用内存最大值,结构体中成员一数据类型占用内存、结构体中成员二数据类型占用内存……结构体中成员 N 数据类型占用内存)
-
如果嵌套共同体,有效对齐值为 Min(编译器默认对齐值,Max(Max(共同体内成员一、共同体内成员二……共同体内成员 N),结构体中成员一数据类型占用内存、结构体中成员二数据类型占用内存……结构体中成员 N 数据类型占用内存))
-
共用体所占内存大小:Max(共同体内成员一、共同体内成员二……共同体内成员 N)
举例
#pramga packnn告诉编译器字节对齐方式为 n 字节对齐
#pramga pack(8)
struct s1{
char a;
int b;
char c;
};
结构体中最大的成员数据类型占用 4 字节,有效对齐值为 Min8,48,4=4;char 为第一个成员,应在结构体偏移量为 0 的地址,占用 1 字节;int 占用 4 字节,要对齐在 Min8,48,4=4 的整数倍位置,即 4 的位置 4,5,6,74,5,6,7;char 占用 1 字节,要对齐在 Min8,18,1=1 的整数倍位置,即 8 位置;因为结构体总大小为有效对齐值的整数倍,所以结构体的大小应为 120 110 11
#pramga pack(8)
struct s1{
char a;
int b;
char c;
};
struct s2{
char a1;
struct s1 S1; //嵌套结构体
double d;
};
结构体 s1 中最大数据类型结构为 int 占用 4 字节,结构体 s2 的有效对齐值为 Min8,Max(4,1,88,Max(4,1,8)=8;char 为第一个成员,应在结构体偏移量为 0 的地址,占用 1 字节;嵌套结构体 s1 占用 12 字节占用 12 字节要对齐在 Min8,48,4=4 的整数倍,即 4(4-15);double 占用 8 字节,要对齐在 Min(8,8)的整数倍位置,即 16(16-23);因为结构体总大小为有效对齐值的整数倍;此时结构体内存大小为 24,满足要求。
#pramga pack(4)
struct s1{
char a;
int b;
union w{
int c;
double d;
}w;
short e;
};
共同体 w 中最大数据类型占用内存为 Max(4,8)=8;结构体 s1 的有效对齐值为 Min(4,Max8,1,4,28,1,4,2)= 4;char 为第一个成员,应在结构体偏移量为 0 的地址,占用 1 字节;int 占用 4 字节,要对齐在 Min4,44,4=4 的整数倍位置,即 4 的位置 4,5,6,74,5,6,7;共同体 w 占 Max4,84,8=8 字节,要对齐在 Min4,124,12=4 的整数倍位置,即 8 的位置 8−158−15;short 占 2 字节,要对齐在 Min4,24,2=2 的整数倍为止,即 1616−1716−17; 因为结构体总大小为有效对齐值的整数倍;所以结构体 s1 的大小需要补位到 4 的整数倍, 即 20 字节。