【内存对齐】第五篇·嵌套构造类型的对齐规则{结构体}

本文深入探讨了内存对齐中结构体数组、共用体包含结构体以及结构体包含结构体的对齐规律。结构体数组的大小等于结构体元素对齐后的大小乘以元素个数,共用体的大小至少等于最大成员的大小,并且是最大非结构体成员大小的整数倍。对于结构体包含结构体的情况,其大小基于所有内外层元素中最大宽度的类型对齐,相当于展开后的大小。这些规则对于理解和优化内存使用至关重要。
摘要由CSDN通过智能技术生成

上一篇:【内存对齐】第四篇·Array、Union内存对齐的规律与原则

首先,定义规则的人应该希望:前面各种构造类型的规则,如果可以递归,就可以用于嵌套的构造类型。所以我们只需要猜想并进行验证即可。根据构造类型的排列组合,我们可以将嵌套方式分为如下几种:

外层类型内层类型
数组结构体
共用体结构体
结构体结构体
结构体数组
数组数组
共用体数组
结构体共用体
数组共用体
共用体共用体

本篇介绍前3种的对齐规则。

数组 { 结构体 } = 结构体数组

结构体作为元素构成的数组,被称为结构体数组。即有一个数组,数组中的每个元素都是一个结构体。那么其对应的每个元素都应该是对齐的,整个数组的大小等于“结构体大小*元素个数”。

struct {char; char; char; }
test[1] Size: 3 Address: 0x00000001004071a4
test[2] Size: 6 Address: 0x00000001004071a4
test[3] Size: 9 Address: 0x00000001004071a8

struct {char; short; }
test[1] Size: 4 Address: 0x00000001004071a4

后面不用再多验证了,结论是:

a. 结构体数组Size=结构体元素元整后的Size*元素个数。
b. 结构体数组的起始Address规则同数组本身规则。

共用体 { 结构体 }

共用体中有成员是结构体,猜测是其Size以最大的成员Size为标准,首地址以Size为标准:

union test_u{
char grass;
char tree;
short leaf;
struct flower {
char color;
};
}test;
Size: 2 Address: 0x00000001004071a2

union test_u{
char grass;
char tree;
short leaf;
struct flower {
char color;
int flavor;
};
}test;
Size: 8 Address: 0x00000001004071a8

union test_u{
char grass;
char tree;
short leaf;
struct flower {
char color;
char flavor;
char type;
};
}test;
Size: 4 Address: 0x00000001004071a4

union test_u{
char grass;
char tree;
char leaf;
struct flower {
char color;
char flavor;
char type;
char habbit;
char lifespan;
};
}test;
Size: 5 Address: 0x00000001004071a4

union test_u{
char grass;
char tree;
int leaf;
struct flower {
char color;
char flavor;
char type;
char habbit;
char lifespan;
};
}test;
Size: 8 Address: 0x00000001004071a8

union test_u{
char grass;
char tree;
int leaf;
struct flower {
char color;
char flavor;
char lifespan;
};
}test;
Size: 3 Address: 0x00000001004071a4

这里出现了一个非常有意思的现象,联合体的大小要大于等于其中的结构体的大小,且为最大成员类型大小的整数倍。所以结论是:

a. 联合体的大小是大于等于 [所有成员中 [最小的 [最大非结构体成员大小的整数倍]]]。
(非常拗口,可以分解为 联合体的大小满足: 1.大于等于所有成员;2. 是所有非结构体成员的整数倍)
b. 联合体的首地址是和Size有关的,规则同联合体本身的规则。

结构体 { 结构体 }

结构体与共用体不一样,没有“共用“,所以可能会有
A. 被嵌套的结构体的大小相当于内部所有结构体展开后,再计算的大小;
或者
B. 内部结构体先做一次计算,再参与到被嵌套结构体的计算中。
实践得真知:

struct test_st{
char meat;
char vegetable;
struct fruit{
char color;
};
}test;
Size: 3 Address: 0x00000001004071a4

struct test_st{
char meat;
char vegetable;
struct fruit{
char color;
char flavor;
char smell;
};
}test;
Size: 5 Address: 0x00000001004071a4

struct test_st{
char meat;
char vegetable;
struct fruit{
char color;
short flavor;
};
}test;
Size: 6 Address: 0x00000001004071a4

内层结构体的size之前已经论述过,应该是4,所以6=1+1+4,说明结构体的成员并没有按照内层结构体的总大小来对齐(否则应为8)。但是否做了展开,并按照short进行对齐了呢?

struct test_st{
char meat;
short vegetable;
char egg;
struct fruit{
char color;
int flavor;
};
}test;
Size: 16 Address: 0x00000001004071b0

根据之前几节的分析,可知内层结构体的size是8,这里假设没有展开,其他结构体成员的大小应该是按照short的大小2对齐,这样size=2+2+2+8 = 14,显然和计算结果不符。
那假设这里做了展开,也就是所有成员按照int的大小4来对齐,那就是2+2+4+8=16,恰好是计算出的结果。这样就清晰了:

结构体嵌套结构体的对齐原则,是按照所有内外层元素中最大宽度的类型来对齐的,相当于将结构体嵌套做展开。

这里还做了另一个实验,为了避免出现结构体表述产生的差异:

struct fruit_st{
char color;
int flavor;
};
struct test_st{
char meat;
short vegetable;
char egg;
struct fruit_st fruit;
}test;
Size: 16 Address: 0x00000001004071b0

可以看到,结论是一样的。
还有一点需要验证,当结构体成员的大小大于内部嵌套的结构体的大小的时候,会如何圆整?

struct fruit_st{
char color;
};
struct test_st{
char meat;
int egg;
struct fruit_st fruit;
}test;
Size: 12 Address: 0x00000001004071a8

所以可以得到结论:

a. 结构体中嵌套结构体,其结构体的Size是相当于将内层结构体展开后,重新组成的整个结构体进行Size的计算。(这里有明显的Recursive适用性)
b. 结构体嵌套结构体,其起始地址与Size相关,其规则与结构体本身规则相同。

连载中… by 2021/08/28

下一篇:【内存对齐】第六篇·嵌套构造类型的对齐规则{数组}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值