引言
通过以前对学习,我们都知道每个不同类型的变量在内存中都会占用不同大小的字节。
char(1字节)
short(2字节)
int(4字节)
long(8字节)
指针(通常4或8字节,取决于编译时是x86环境还是x64环境,x64是4字节)
float通常和int一样(4字节)
double通常是8字节
而结构体由多个成员组成,每个成员可以是不同的数据类型,比如整数、浮点数、字符、数组、指针等。通过结构体,可以将这些相关联的数据封装在一起。
struct 结构体名 {
数据类型 成员1;
数据类型 成员2;
// 更多成员...
};
那么结构体所占用的内存大小是否是简单的成员变量的大小相加呢?
我们看看这两个结构体代码的计算:
两个结构体虽然成员变量相等,但结果不是简单字节的相加,且由于顺序不相等结果也不相等。
那为什么会这样呢?这就是有关结构体内存对齐的知识点了。容我慢慢道来。
结构体内存对齐规则
1.结构体的第⼀个成员要对⻬到起始位置偏移量为0的地址处
2.其他成员变量要对⻬到地址为对⻬数的整数倍的地址处。
对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量字节⼤⼩相比较的较⼩值。
我们常用的VS 中默认对齐数为 8
Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,取所有对⻬数中最⼤的数,就是最大对齐数)的整数倍。
4. 如果嵌套了结构体,被嵌套的结构体对⻬到结构体⾃⼰的成员中最⼤对⻬数的整数倍处就行,**结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)**的整数倍。
没有嵌套的结构体内存对齐
这里我们还是以代码举例:
example 1
struct Example_1 {
//自身大小 默认对齐数 对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
char a; // 1字节 8 1
int b; // 4字节 8 4
char c; // 1字节 8 1
}one;
example 2
struct Example_2 {
//自身大小 默认对齐数 对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
int a; // 4字节 8 4
char b; // 1字节 8 1
char c; // 1字节 8 1
}two;
相信大家通过以上过程和思路,都能做到举一反三的吧,嘻嘻,那我就结束了。
有嵌套的结构体内存对齐
struct Example_1 {
//自身大小 默认对齐数 对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
char a; // 1字节 8 1
int b; // 4字节 8 4
char c; // 1字节 8 1
}one;//最大对齐数为4
struct Example_2 {
//自身大小 默认对齐数 对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
int a; // 4字节 8 4
struct Example_1 one;//嵌套的结构体对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处就行,那么对齐数就是4.
char c; // 1字节 8 1
}two;
int main()
{
printf("%d\n", sizeof(one));
printf("%d\n", sizeof(two));
return 0;
}
这里的struct Example_2 two结构体中嵌套了结构体struct Example_1 one,那么我们看看结果会是啥呢
看我慢慢给你分析:
通过上面(example 1)中的代码我们已经知道结构体struct Example_1 one的大小为12。
这就是嵌套了结构体的结构体大小的求法。
修改默认对齐数
#pragma 这个预处理指令,可以改变编译器的默认对⻬数。
Linux中 gcc 由于没有默认对齐数,所以无法修改。
struct Example_1 {
//自身大小 默认对齐数 对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
char a; // 1字节 8 1
int b; // 4字节 8 4
char c; // 1字节 8 1
}one;
#pragma pack(1)//设置默认对⻬数为1
struct S
{
//自身大小 默认对齐数 对齐数(取对⻬数 与 该成员变量 字节⼤⼩相比较的较⼩值)
char c1; // 1 1 1
int i; // 4 1 1
char c2; // 1 1 1
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{
printf("%d\n", sizeof(one));
//猜猜结果是多少
printf("%d\n", sizeof(struct S));
return 0;
}
根据我们以上的思路,可以简单的推断出这个过程。
由于对齐数都为1,因为任何数都是1的整数倍,那么所有类型都是自上而下逐个排序,那么结果就是简单的所有类型字节大小相加了。