C语言结构体的大小与内存对齐问题

本文探讨了C/C++编程中内存对齐的规则,解释了为何结构体的实际大小超过理论总和,以及内存对齐对性能的影响。重点介绍了VS2019和Linux/GCC的默认对齐策略,并讨论了如何调整编译器对齐数以优化存储和性能。
摘要由CSDN通过智能技术生成

引例
本次代码均运行在32位机,VS2019环境下
分析如下一段代码:

int main() {
	struct S {
		char c1;
		int num;
		char c2;
	}s1;
	printf("%d", sizeof(s1));
	return 0;
}

理论上来讲这个结构体的大小就是各个成员变量大小的总和对吧?但是实际结构体的大小并不是这么回事! 实际输出是12个字节。这是为什么呢?这就是这次我们主要探讨的东西 “内存对齐”

内存对齐的规则

我们首先需要了解结构体内存对齐的规则:

1、第一个成员变量存放在与结构体地址偏移量为0的地址处,也就是首地址
2、其他成员要存放在对齐某个数字(对齐数)的整数倍地址处
对齐数:取编译器默认的一个对齐数和该成员变量大小 的较小值

  • VS中默认对齐数为8
  • Linux也就是Gcc编译器没有默认对齐数,对齐数就是该成员自身大小

3、结构体的总大小为最大对齐数(每个成员的对齐数,取其中对齐数最大的成员的对齐数)的整数倍。举个例子:若最大对齐数 8,结构体存储了11个字节,那么再往后申请5个字节的空间来对齐到16.
4、如果结构体内嵌套结构体了,嵌套的结构体对齐到自身成员的最大对齐数的整数倍,而结构体的整体大小就需要对齐到所有最大对齐数的整数倍处。

讲完规则现在我们回头来看下引例中这段代码的结构体在内存中到底是如何分布的:

在这里插入图片描述
这便是结构体s1在内存的分布情况,我们可以清楚的看到他分配了12个字节空间。在VS的调试界面也可以清楚看到:
为了方便观察我分别给成员变量赋了值
在这里插入图片描述

至此我们就大概了解了内存对齐的规则,下边我们再来思考 编译器为什么要浪费空间来这么干呢?这么做有什么好处吗?

  1. 平台原因(移植性):
    不是所有的硬件平台都是可以从任意地方读取写入数据的,某些平台只能在某些特定的地址来操作数据,否则会抛出硬件异常

  2. 性能原因:
    数据结构(特别是栈)应尽量将数据存放在自然边界上对齐。
    原因在于:访问未对齐的数据处理器可能需要两次访问才能做到, 而对齐到数据只需要一次访问。
    总体来讲,结构体这个数据类型就是用存储空间来换取存取速度的做法

编译器的默认对齐数是否可以修改?如何修改?

这个问题的答案是肯定的,他是可以修改的
我们可以通过如下两条代码来修改和恢复编译器默认的对齐数:

#pragma pack(1)//将对齐数修改为1
#pragma pack()//将对齐数恢复为默认值

一般情况下我们设置的对齐数为2的次方数,并且设计结构体成员的时候要尽量让占用空间较小的成员集中在一起,这样才能最大限度的节省空间并且提高效率!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栗悟饭&龟波气功

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值