这个话题还是很早以前讨论过,当时并没有好好的理解,最近在复习知识的时候又重新看了一遍资料,自己做一下总结,也希望后面有人需要学习时可以对他有所帮助。以下我会举两个结构体的例子,分别画图的方式表达对齐的原则。
结构体对齐的公式
记住以下这些规则,把结构体往里面套就可以了。结构体对齐的原则就是牺牲空间的方式来减少时间的消耗,空间用完还可以复用,而时间过去了就再也不会回来了。
- 以 #pragma pack(x) 中 x 的大小和结构中占用空间最大的成员做比较,取小值为 n(外对齐依据)
- 以 n 值和结构体每个成员比较,得出结果列表为 m[x]
- 根据每个成员的大小依次向内存中填充数据,要求填充
成员的起始地址
减去构体起始地址
的差都可以整除 m[x] ,如不能整除则向后移动,直到可以整除再填充成员到内存(内对齐依据) - 当全部成员填充完毕后所占用的字节若不能整除 n,则扩充内存到可以整除 n 为止。
案例一
我们来看一个简单的案例,#pragma pack(4) 为 4,结构体中有 char、short、int 3个成员,其对齐的方式如下图表示:
代码语言:javascript复制#include <stdio.h>
#pragma pack(4)
typedef struct data
{
char a;
short b;
int c;
} DATA, *PDATA;
int main(int argc, char* argv[])
{
printf("sizeof(DATA) = %lun", sizeof(DATA));
return 0;
}
以上代码运行后,得到如下结果:
代码语言:javascript复制mycode@vmware:~/Desktop$ gcc struct.c -o struct_size
mycode@vmware:~/Desktop$ ./struct
sizeof(DATA) = 8
案例二
这个案例中,我们把 #pragma pack(8) 设定为 8,结构体中有三个成员 char、double、int,其对齐方式如下图:
代码语言:javascript复制#include <stdio.h>
#pragma pack(8)
typedef struct data
{
char a;
double b;
int c;
} DATA, *PDATA;
int main(int argc, char* argv[])
{
printf("sizeof(DATA) = %lun", sizeof(DATA));
return 0;
}
是不是有点毁三观啊?以上代码运行后的结果,的确就是 24。
代码语言:javascript复制mycode@vmware:~/Desktop$ gcc struct_size.c -o struct_size
mycode@vmware:~/Desktop$ ./struct_size
sizeof(DATA) = 24
要注意的是,如果你把这个案例中 int 和 double 成员颠倒个位置,再编译代码你会发现其占用空间变成了 16,按上面的规则推断一下,很明显,首先是第二个成员 int 在内存的第 4 号位置就可以驻留了,第三个成员 double,在第 8 号位置也同样可以驻留。最终大小会变成 16 个字节。