前言:本人为C语言初学者,学识尚浅,研究程度存在很大的局限性,眼界很窄。以下所有观点仅代表个人见解和思路,各位游刃有余的前辈可以给予批评和指正!各位与鄙人同路的学子可相互探讨、发表看法,交换观点!
如果你学习了结构体,那么应该不至于对它太陌生:
struct tag
{
member - list;
};
int main()
{
struct tag s = {0};
return 0;
}
但是结构体在内存中占多大空间呢?
例如:
struct test
{
char a;
int b;
double c;
};
如果按照我们的正常思维,它所占的空间应该是:1(char)+ 4(int)+ 8(double) = 13byte
但事实是否就如我们所想的呢?我们不妨用 sizeof 来计算一下大小:
struct test s = {0};
printf(“%d\n”, sizeof(s));
而答案却不如我们所料,这到底是为什么呢?
所以进入我们今天要讨论的话题:结构体内存对齐
首先,我把4条规则先罗列于此,然后分析:
1.第一个成员在结构体变量偏移量为0的地址处
2.其他成员变量要对其到对其数的整数倍的偏移量地址处
(对齐数:编译器默认的一个对齐数与该成员大小的较小值,VS默认为8)
3.结构体总大小为最大对齐数的整数倍
4.如果结构体中嵌套了结构体,则嵌套的结构体对齐到自己结构体中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
struct test
{
char a;
int b;
double c;
};
就这一串而言,我们先凭借前三条分析为何为16byte。
这是我们的内存段,依据第一条规定,char 类型直接存储在偏移量为0的位置,即如下:
接下来是int类型,依据第二条规定,我们首先要找到对齐数:int类型为4,VS默认为8,4和8中取一个较小值,即为4。所以int的起始位置应该是偏移量为4的倍数的地方,即偏移量为4的地方:
接下来是 double 类型,还是要找到对齐数,因为其大小都是8,所以对齐数也就是8,而从偏移量为8的倍数开始,刚好就是 int 下面的一块空间,即存放如下:
而至于第三步,现在整个结构体所占空间是 16byte(0~15),刚刚我们获得的对齐数有 int 的4和double 的8,所以取最大数是8,而 16byte 刚好又是8的整数倍,所以这里16即为最终结果。
当然,这里或许第三条规定不能很好体现,如果我们把结构体的 double 修改成 char :
struct test
{
char a;
int b;
char c;
};
前两步同理,而第三步时,我们的 char 类型为1,VS默认为8,所以取较小值为1,即其实 char 什么位置都可以放,因为不管哪个数都是1的倍数:
这里整个结构体所占空间为9,但是在所有对齐数中最大的是 int 的4,9不是4的倍数,所以结构体只能在11的位置真正的结束,营造出 12byte 的空间。
以下用绿色标记的空间是未使用的,换句话说,浪费了:
既然这样,前三条规定我想大家已经有了清楚的认知,那么对于第四条规定,我们还得举例说明:
struct test1
{
char a;
int b;
char c;
};
struct test2
{
int i;
struct test1 s1;
char ch;
};
int main()
{
struct test2 s2 = {0};
printf("%d\n", sizeof(s2));
return 0;
}
1.放 int 类型:
2.放结构体类型:
此结构体s1已在上文中详细解析,其所占空间为12。而在结构体test1中,其最大对齐数是4,所以结构体要放在偏移量为4的整数倍的位置,刚好int类型放完下一位就是4,所以是这样放的:
3.放 char 类型,char 类型的对齐数肯定是1,所以往后放就OK了:
当然,最后一步是计算整个结构体空间的大小,但这时我们的结构体大小为 17byte(0~16),而在所有的对齐数中,int 为4,struct test1 为4(取这一结构体中最大对齐数),char 为1,所以取所有值的最大值,也是4,但是17不是4的整数倍,只能到20byte才行,所以这个结构体最后结束在19,如下:
END