前言
学C的同学应该知道~想精通C语言就不得不面对—指针与内存
续上次指针进阶,这一章我来聊一聊C语言内存对齐的问题
学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的😁
思考
#include<stdio.h>
typedef struct s1
{
char a;
char b;
int c;
}s1;
typedef struct s2
{
char a;
int c;
char b;
}s2;
int main()
{
//内存对齐的现象
printf("%d\n", sizeof(s1));
printf("%d\n", sizeof(s2));
return 0;
}
很显然这一段代码就是计算s1与s2向系统申请的内存大小
我:两个char类型各为一,再加上应该int类型的四,结果就是六
诚挚的乔治:你说的对,但不完全对,在结构体中会出现内存对齐的现象,不信?看结果
别慌,看到文章的最后,你(也许)就会恍然大悟
在结构体中,内存不是成员的大小之和
📃结构体在内存中开辟空间时内存对齐的规则:
1.结构体中的第一个成员存放在这个结构体的零偏移处,故第一个成员char类型的的偏移量为零2.从第二个成员开始,每个成员都要对齐到成员对齐数的整数倍
(对齐数--成员自身大小与默认对齐数的最小值的整数倍,如果自身大小是四,默认对齐数是八,最终的对齐数就是四的倍数),一般情况下默认对齐数就是八。
3.结构体的总大小必须是最大对齐数的整数倍 。
(最大对齐数就是每个成员对齐数中的最大值)
4.如果结构体中嵌套结构体的情况下,嵌套的结构体就对齐到自己成员对齐数的最大对齐数的整数倍处,结构体的总大小就是最大对齐数(含嵌套的结构体成员)的整数倍。
下面其中的一个结构体进行分析:
先向大家介绍一下本章的配角—offsetof
offsetof的返回值就是距离这个结构体(自定义类型)起始位置的值
参数就是结构体的名称和结构体成员的名称。
#include<stddef.h>
#include<stdio.h>
typedef struct s
{
char a;
int b;
char c;
}s;
int main()
{
//offsetof-是指偏移量
printf("%d\n", offsetof(s,a));
printf("%d\n", offsetof(s,b));
printf("%d\n", offsetof(s,c));
return 0;
}
char a; //因为char a是结构体第一个成员,所以偏移量就是零
int b; //自身大小:4 默认对齐数:8 对齐数:4的倍数即可,所以偏移量就是四
char c; // 自身大小:1 默认对齐数:8 对齐数:1的倍数即可,所以偏移量就是八
又因为最终的结构体大小是成员最大对齐数的倍数,也就是四的倍数,所以最终的结构体的大小应该就是十二。
到这里是不是有一定的思路了,别急,再来一道试试吧
#include<stddef.h>
#include<stdio.h>
typedef struct s
{
double a;
char b;
int c;
}s;
int main()
{
//offsetof-是指偏移量
printf("%d\n", offsetof(s,a));
printf("%d\n", offsetof(s,b));
printf("%d\n", offsetof(s,c));
printf("%d", sizeof(s));
return 0;
}
结果如下:
是不是跟你想的一样呢?
同样的,用一样的方法进行解释
double a; //因为double a是结构体第一个成员,所以偏移量就是零
char b; //自身大小:1 默认对齐数:8 对齐数:1的倍数即可,所以偏移量就是八
int c; //自身大小:4 默认对齐数:8 对齐数:4的倍数即可,所以偏移量就是十二
最终结构体的大小就是四的整数倍十六
下面给应该结构体嵌套结构体的例子
#include<stdio.h>
#include<stddef.h>
typedef struct s1
{
char i;
char j;
int k;
}s1;
typedef struct s2
{
char a;
int c;
s1;
}s2;
int main()
{
printf("%d\n", offsetof(s2, a));
printf("%d\n", offsetof(s2, c));
printf("%d", sizeof(s2));
return 0;
}
我相信此时的你一定会计算结构体想系统申请的大小,以及内存对齐是咋回事
其实,内存对齐也就那么回事儿~
为什么存在内存对齐
知道怎样计算后,你是否和我一样思考
为什么内存的申请不能想main函数中的内存申请一样,要多少就申请相应大小的空间,这样既省内存,也不用考虑这么多。
1.平台的原因
所谓平台原因就是与硬件有关,硬件不能访问内存中的每一个空间,换句话说,就是按一定的规律进行访问,这样内存对齐就起到了很好的作用2.性能的原因
数据结构(尤其是栈),应该尽可能的在自然边界上对齐因为我们的CPU访问空间,就是一次性按四个字节的空间来访问,内存对齐在一定的时候避免了访问一次的空间进行了二次访问
如下访问应该int类型内存对齐后只需要访问一次
总的来说内存对齐就是拿空间换取时间
当然,我们可以实现内存对齐之上,也可以进行省一定空间
就想博客开头一道题,一模一样的代码,最终的结构体的大小却不一样,这种就是优化版的结构体
这里给一个小的技巧,就是把空间小的成员尽量放在一起
欢迎点赞收藏加关注,如若有问题可以提出来😁😁😁😁
欢迎大家来评论区理性交流、学习,咱们下期见!!