这是我参与更文挑战的第3天,活动详情查看: 更文挑战
结构体内存对齐规则
规则1. 数据成员对⻬规则:
结构(struct)(或联合(union))的数据成员,第 ⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要 从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组, 结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存 储。
规则2. 结构体作为成员:
如果⼀个结构体⾥有某些结构体成员,则结构体成员要从 其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a⾥存有struct b,b ⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.)
规则3. 收尾⼯作:
结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤成员的整数倍.不⾜的要补⻬。
示例
我们用占用大小表示当前类型的数据占用的空间大小,用存储位置表示占用的存储地址,其中()
表示因为某些对齐规则需要“牺牲“掉的空间,[]
表示数据实际存储的空间;
- 示例1
struct GCStruct1 { 占用大小 存储位置
double a; // 8 [0-7]
char b; // 1 [8]
int c; // 4 (9-11)[12-15]
short d; // 2 [16-17]
}struct1;
GCStruct1
的成员变量只占用了15个字节;- 因为规则1,
(9-11)
的位置需要对齐而空出来,实际上需要的空间有[0-17]
这18个字节; - 因为规则3,必须是最大成员
double型
8的倍数; GCStruct1
实际占用24个字节;
- 示例2
struct GCStruct2 { 占用大小 存储位置
double a; //8 [0-7]
int b; //4 [8-11]
char c; //1 [12]
short d; //2 (13)[14-15]
}struct2;
GCStruct2
的成员变量只占用了15个字节,- 因为规则1,
(13)
的位置需要对齐而空出来,实际上需要的空间有[0-15]
这16个字节; - 因为规则3,必须是最大成员
double型
8的倍数,16符合条件; GCStruct2
实际占用16个字节;
- 示例3
struct GCStruct3 { 占用大小 存储位置
double a; //8 [0-7]
int b; //4 [8-11]
char c; //1 [12]
short d; //2 (13)[14-15]
int e; //4 [16-19]
struct GCStruct1 str; //24 (20-23)[24-41]
}struct3;
GCStruct3
的成员变量只占用了8+4+1+2+4+24=43
个字节- 因为规则1,
(13)
的位置需要对齐而空出来 - 因为规则2,成员变量
str
存储时需要从GCStruct1
内部最大的成员变量double型
8的倍数开始存储,所以(20-23)
的位置需要对齐而空出来,str
需要的实际空间是18个字节(不使用规则3对齐),存储的位置是[24-41]
这18个字节,此时struct3一共占用[0-41]
共42个字节; - 因为规则3,必须是最大成员
double类型
8的倍数,则最终GCStruct3
实际占用48个字节;
代码验证
最终代码执行结果与研究一致;
结构体规则补充
- 当结构体作为成员变量被嵌套进其他结构体时,其size为只受规则2限制,不受规则3限制,不需要处理为最大的整数倍,而是等加到外部之后统一处理;
- 当结构体作为成员变量被嵌套进其他结构体时,被嵌套的结构体不可以作为外层结构体的最大成员来计算最终size,需要拆分后将其成员变量与外层放到一起后找出最大成员的size进行整数倍对齐;