结构体内存字节对齐规律
2020-09-08 本文已影响0人
CrazySnow
结构体是由一批数据组合而成的一种新的数据类型。组成结构型数据的每个数据称为结构型数据的“成员”。
结构体指针的大小是8字节,结构体的大小是根据结构体成员的大小累积计算。
字节对齐的好处
内存存取粒度:处理器并不是按字节块来存取内存的.它一般会以双字节
,四字节
,8字节
,16字节
甚至32字节
为单位来存取内存.我们将上述这些存取单位称为内存存取粒度。
- CPU的
数据总线
宽度决定了CPU对数据的吞吐量 - 64位CPU一次处理
64 bit
也就是8个字节
的数据,32同样,每次处理4个字节
的数据
字节对齐规则
基本数据类型的大小.png- 数据成员对齐规则:
struct
或者union
的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如数据、结构体等)的整数倍开始 - 数据成员为结构体:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储
结构体的整体对齐规则:结构体的总大小,即sizeof
的结果,必须是其内部做大成员的整数倍,不足的要补齐
以下面结构体为例,计算Student结构体的大小:
struct Student {
bool sex;
//$\color{red}{1个字节}$ (0,1) 放在第0位,长度为1;起始位置是0
short int age;
// $\color{red}{2个字节}$ (2,2)放在第2位长度为2;起始位置是2
//$\color{red}{*为什么没有放在第一位,起始位置必须是长度的整数倍,1不是2的整数倍}$
void *address;
// $\color{red}{8个字节}$(8,8)放在第8位,长度是8;起始位置是5,6,7,8;8是8的整数倍,所以起始位置是8
float grade;
// $\color{red}{4个字节}$(16,4)放在第16位,长度是4;起始位置是16;
char name[9];
// $\color{red}{9个字节}$(20,9)放在第29位,长度为9;起始位置是20;
// $\color{red}{*char是一个字节,虽然char name[9]占9个位置,但是起始位置必须是长度(数据类型的长度)的倍数}$
};
结构体的大小是结构体中最大元素的整数倍,Student结构体中,char
的长度是8
,故Student
结构体的大小为32
;
针对结构体嵌套的情况
struct Student2 {
bool sex;
short int age;
void *address;
float grade;
char name[9];
Student1 stu;
};
结构体嵌套,最终的大小并不是Student2
结构体内最大的元素的倍数,而是Student1
和Student2
所有子元素里,最大的那一个的倍数,所以Student2
的大小是8的倍数,按照上面的排列规则,得出结果是53
,但是结果必须是8
的倍数,故最终结果是56
。
字节重排
当我们在定义结构体时,如果数据成员的定义顺序安排的不合理就有可能会导致多余内存空间的占用和浪费。 为了达到最佳内存空间占用
,系统在计算内存大小的时候,会对结构体内的元素进行重排,按照从小到大的原则重新排列
,下图是Student1
重排后的结果。