【C语言系列】-结构体中的内存对齐

【C语言系列】-结构体中的内存对齐,第1张

【C语言系列】-结构体中的内存对齐

目录

        前言

        思考 

结构体在内存中开辟空间时内存对齐的规则:

为什么存在内存对齐

1.平台的原因

2.性能的原因


前言

学C的同学应该知道~

想精通C语言就不得不面对—指针与内存

续上次指针进阶,这一章我来聊一聊C语言内存对齐的问题

学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的

思考 
#include
typedef struct s1
{
	char a;
	char b;
	int c;
}s1;
typedef struct s2
{
	char a;
	int c;
	char b;
}s2;
int main()
{

	//内存对齐的现象
	printf("%dn", sizeof(s1));
	printf("%dn", sizeof(s2));
	return 0;
}

很显然这一段代码就是计算s1与s2向系统申请的内存大小

我:两个char类型各为一,再加上应该int类型的四,结果就是六

诚挚的乔治:你说的对,但不完全对,在结构体中会出现内存对齐的现象,不信?看结果

别慌,看到文章的最后,你(也许)就会恍然大悟


在结构体中,内存不是成员的大小之和

结构体在内存中开辟空间时内存对齐的规则:

1.结构体中的第一个成员存放在这个结构体的零偏移处,故第一个成员char类型的的偏移量为零

2.从第二个成员开始,每个成员都要对齐到成员对齐数的整数倍

(对齐数--成员自身大小与默认对齐数的最小值的整数倍,如果自身大小是四,默认对齐数是八,最终的对齐数就是四的倍数),一般情况下默认对齐数就是八。

3.结构体的总大小必须是最大对齐数的整数倍 。

(最大对齐数就是每个成员对齐数中的最大值)

4.如果结构体中嵌套结构体的情况下,嵌套的结构体就对齐到自己成员对齐数的最大对齐数的整数倍处,结构体的总大小就是最大对齐数(含嵌套的结构体成员)的整数倍。

 下面其中的一个结构体进行分析:

 先向大家介绍一下本章的配角—offsetof

 offsetof的返回值就是距离这个结构体(自定义类型)起始位置的值

参数就是结构体的名称和结构体成员的名称。

#include
#include
typedef struct s
{
	char a;
	int b;
	char c;
}s;
int main()
{
	//offsetof-是指偏移量
	printf("%dn", offsetof(s,a));
	printf("%dn", offsetof(s,b));
	printf("%dn", offsetof(s,c));
	return 0;
}


 

 char a; //因为char a是结构体第一个成员,所以偏移量就是零
  int b;      //自身大小:4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是四
 char c;    // 自身大小:1    默认对齐数:8   对齐数:1的倍数即可,所以偏移量就是八

又因为最终的结构体大小是成员最大对齐数的倍数,也就是四的倍数,所以最终的结构体的大小应该就是十二。

 

 到这里是不是有一定的思路了,别急,再来一道试试吧

#include
#include
typedef struct s
{
	double a;
	char b;
	int  c;
}s;
int main()
{
	//offsetof-是指偏移量
	printf("%dn", offsetof(s,a));
	printf("%dn", offsetof(s,b));
	printf("%dn", offsetof(s,c));
	printf("%d", sizeof(s));
	return 0;
}

结果如下:

是不是跟你想的一样呢?

同样的,用一样的方法进行解释

double a;     //因为double a是结构体第一个成员,所以偏移量就是零
    char b;     //自身大小:1    默认对齐数:8   对齐数:1的倍数即可,所以偏移量就是八
    int  c;        //自身大小:4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是十二

最终结构体的大小就是四的整数倍十六

下面给应该结构体嵌套结构体的例子

#include
#include
typedef struct s1
{
	char i;
	char j;
	int k;
}s1;
typedef struct s2
{
	char a;
	int c;
	s1;
}s2;
int main()
{

	printf("%dn", offsetof(s2, a));
	printf("%dn", offsetof(s2, c));
	printf("%d", sizeof(s2));
	return 0;
}

 

 

 我相信此时的你一定会计算结构体想系统申请的大小,以及内存对齐是咋回事

其实,内存对齐也就那么回事儿~

为什么存在内存对齐

 知道怎样计算后,你是否和我一样思考

为什么内存的申请不能想main函数中的内存申请一样,要多少就申请相应大小的空间,这样既省内存,也不用考虑这么多。

1.平台的原因

所谓平台原因就是与硬件有关,硬件不能访问内存中的每一个空间,换句话说,就是按一定的规律进行访问,这样内存对齐就起到了很好的作用

2.性能的原因

数据结构(尤其是栈),应该尽可能的在自然边界上对齐

因为我们的CPU访问空间,就是一次性按四个字节的空间来访问,内存对齐在一定的时候避免了访问一次的空间进行了二次访问

如下访问应该int类型内存对齐后只需要访问一次

 总的来说内存对齐就是拿空间换取时间

当然,我们可以实现内存对齐之上,也可以进行省一定空间

就想博客开头一道题,一模一样的代码,最终的结构体的大小却不一样,这种就是优化版的结构体

这里给一个小的技巧,就是把空间小的成员尽量放在一起

欢迎点赞收藏加关注,如若有问题可以提出来 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5713514.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存