C语言结构struct的内存对齐
操作系统的内存对齐问题对于低层程序设计来说非常重要,对理解内存对齐原理及方法则有助于帮助程序员判断访问非法内存。
1.结构struct默认的内存对齐原则
struct内存默认的内存对齐原则主要有两个,一个是结构成员之间的内存对齐,另一个是结构体整体的内存对齐。
1.1 成员之间的对齐原则
C编译器缺省的结构成员变量内存对齐为“N字节对齐”,N即该成员数据类型的长度。例如,int型成员变量的自然对界条件为4字节对齐,即该成员变量的起始偏移能够被4整除,如果不能被4整除,则在前一个成员变量后面添加适当的空字节,最终使得int型成员变量的起始偏移能够被4整除。
1.2 结构体整体的对齐原则
C编译器缺省的结构整体的内存对齐条件为:结构所占内存大小要能够被结构中成员变量中最大长度整除。例如结构test所占的内存大小必须能够被sizeof(double)=8所整除
struct test
{
char ch1;
int i1;
double d1;
};
如果不能被整除,则在最后一个成员变量后面添加适当的空字节,最终使得test结构所占的内存能够被8整除。
2 默认对齐方式下,计算结构体大小的流程
可以根据如图1所示的流程,对默认对齐方式下结构体的大小进行计算。
对于如下定义的结构体Test
struct Test
{
char ch1;
char ch2;
double f1;
int ch3;
};
其在内存中所占的大小为24字节。
3 内存对齐方式的改变
可以使用预编译指令#pragma pack(n)改变内存的对齐方式,其中n的取值为1,2,4,8,16,C编译器将按照n个字节对齐。
3.1 对齐原则
当使用预编译指令改变了内存的对齐方式后,其对齐原则也会做相应的改变。对比“1.1 成员之间的对齐原则”中介绍的原则,此时成员变量的起始偏移不是能够被该变量的长度所整除,而是能够被该变量长度与n的最小值所整除。同理,对比“1.2 结构体整体的对齐原则”中介绍的原则,结构所占内存大小不是能够被结构中成员变量中最大长度整除,而是能够被成员变量中最大长度与n的最小值所整除。
3.2 判断结构大小的流程图
在修改了内存的对齐方式之后,判断结构大小的流程图如图2所示。对于如下定义的结构体Test
#pragma pack(4)
struct Test
{
char ch1;
char ch2;
double f1;
int ch3;
};
其在内存中所占的大小为16。
图1 默认对齐方式,计算结构体大小的流程