结构体中的内存对齐
内存对齐规则
在C语言中,结构体的内存布局并不是简单地将成员依次排列在内存中,而是遵循一定的内存对齐规则。这些规则确保了数据结构在内存中存储的方式既高效又符合硬件平台的限制。
问题提出
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
int i;
char c1;
char c2;
};
int main()
{
printf("%d\n",sizeof(struct S1));
printf("%d\n",sizeof(struct S2));
return 0;
}
运行结果:
许多小伙伴也许会疑惑为什么两个结构体的大小不一样呢?
这里我们就要提出今天的主题:结构体中的内存对齐
由上述的代码结构我们可以得出结果分析得出:结构体成员不是按照顺序在内存中连续存放的,而是有一定的对齐规则;
具体规则
首个成员对齐:结构体的第一个成员从偏移量为0的位置开始存储。
后续成员对齐:从第二个成员开始,每个成员都要对齐到其大小和平台默认对齐数之间的较小值。
结构体总大小:结构体的总大小必须是所有成员对齐数中的最大值的所有倍数。
嵌套结构体对齐:嵌套结构体对齐到的是内部最大对齐数的倍数。
这些规则确保了结构体在内存中的布局优化,提高访问效率,并符合不同硬件平台的限制。
下面我们以具体的实例来深入理解上述规则(默认对齐数是8):
eg1:
struct S1
{
char c1;
int i;
char c2;
};
我们可以通过画内存示意图来解释为什么S1的内存大小为12
struct S2
{
int i;
char c1;
char c2;
};
通过上述两个例子我们可以得出,即使两个结构体中的成员变量一样,但顺序不一样也会影响结构体的大小。
在设计结构体,既要对齐,又要节省空间的做法是:
让占用空间小的成员尽量集中在一起。
对齐原因
为什么会出现内存对齐这样的规则呢?一般来说有两个方面的原因:
1.平台原因:
不是所有的硬件平台都支持访问任意地址的任意数据,某些硬件平台只能支持在某些特定类型的数据,否则会抛出硬件异常。
2.性能原因:
数据结构(栈)应尽可能地在自然边界上,原因在于为了访问未对齐的内存,处理器上需要两次访问,如果对齐只需要一次访问。
总的来说:
结构体的内存对齐是一种拿空间换时间的做法。
修改默认对齐数
#pragma pack(N)//将默认对齐数修改为N
结构体
##pragma pack()//取消默认对齐数
结构体传参
#include<stdio.h>
struct S
{
int data[100];
int num;
};
void Print1(struct S s)
{
printf("%d\n", s.num);
}
void Print2(struct S* s)
{
printf("%d\n", s->num);
}
int main()
{
struct S s = { {1,2,3},100 };
Print1(s);
Print2(&s);
return 0;
}
上述Print1和Print2两种传参方式都是可行的,但优选Print2
原因:
函数传参时,参数需要压栈,会有时间和空间上的系统开销。如果传递一个结构体对象,结构图过大,参数压栈的系统开销会比较大,导致性能下降
结论:
结构体传参数,要传结构体的地址
总结
结构体内存对齐是C语言中一项重要的内存管理特性,它优化了数据的存储和访问效率。在设计数据结构时,应考虑对齐规则,以达到性能和空间的最佳平衡。
标签:struct,int,char,内存,体中,对齐,结构 From: https://blog.csdn.net/qq_67411584/article/details/137593188