c语言结构体内存对齐四大规则
规则一、
结构体成员的内部偏移量(内部地址)要被这个成员的数据类型大小整除!
简单来说,就是结构体的内存从零开始数,如果要放什么数据类型的变量对应的位置要能被该数据类型大小整除,如果不能,就往后找。
如果我定义了一个char和int类型的数据
struct student{
char a;
int b;
}
char是一个字节,整除起始0位置(每个数据类型在开始都能整除),int类型是四个字节所以存储时要找四的倍数,所以会空出三位,这个也要算到结构体内存中。所以如果我们用sizeof()来计算student的大小会得到8个字节的大小。规则一就介绍完了,可以用编译器多试试。
规则二、
整个结构体的大小,必须是最大成员的size的整数倍,否则需要在末尾补充空白字符
这个就很容易理解了,通过规则一,计算出的总大小,然后除以最大数据结构(占字节最大的数据类型)如果可以整除,那不用补,反之,要补。
如果我定义了一个char和int类型的数据
struct student{
int a;
char b;
}
这个如果按照规则一计算结构体内存应该为五个字节,但是编译器运行结果为8个字节。就是因为规则二,补了空白字符,使得内存大小可以被整除,规则二也讲完了。
规则三、
对于结构体中的结构体(结构体的嵌套),按照结构体展开后的内存对齐来处理
就是,按照你嵌套结构体的最大数据类型大小来对齐起始位置,后面的拆开融入到大结构体内
举个例子,就好像大塑料袋套小塑料袋,我们是将小塑料袋内最大数据类型大小按照规则一确定起始位置,
然后,把小塑料袋拆开,排列
struct A {
int a;
double b;
};
struct B {
char c;
struct A d;
};
int main()
{
struct A num1;
struct B num2 = { 1,{0,1} };
printf("%d ", sizeof(num1));
printf("%d ", sizeof(num2));
unsigned char* p = (unsigned char*)&num2;
for (int i = 0; i < sizeof(num2); i++)
{
printf("[%X]", *p);
p++;
}
}
由运行结果我们可以理解规则三的意思
画图理解一下
拆开B
至此,规则三就讲解完了。
规则四、
人为规定的特殊规则!!!
用#pragma pack(起始位置为什么的倍数)来规定
#pragma pack(2)
struct A {
char a;
int b;
char c;
};
int main()
{
struct A num1;
printf("%d ", sizeof(num1));
}
这个规则替代了规则一,但是如果人为规则所得内存值比规则一大,则仍按规则一的内存。
总结:
以上规则都是为了规定内存,方便程序员管理,在写程序时,应该要考虑如何使内存足够小。在嵌入式开发和物联网工程中,第四条人为规则一般取1,即不存在空白区域,完全使用内存。