C语言中 结构体的内存对齐 结构体的大小

关于结构体,我们可以深入探讨一个话题,计算结构体的大小。

当然我们计算结构体的大小就需要知道结构体的内存对齐.

首先,我们可以先来看一个例子

这里有两个结构体类型,他们的成员都是两个 char 一个int,那么它们的大小是多少呢?一个char 一个字节,一个int 四个字节,那么两个char 一个int就是6个字节,那么结果输入真的是这样吗?

很显然结果并不是6个字节,那么结构体在内存中是怎么存放的呢?

这就涉及到了结构体在内存中的内存对齐

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

1.结构体第一个成员变量对齐结构体变量的起始位置偏移量为0的地址处。

内存会为结构体创建一块空间

假设这就是内存为结构体创建的空间,蓝线就是结构体变量的起始位置,每个方格代表1个字节,偏移量就是距离起始位置相差多少,第一块格子距离起始位置相差为0,所以偏移量是0

第一个成员变量对齐,一定是从偏移量为0的地址开始,假如是一个字节,就在这里放一个字节,假如是两个字节,就按照顺序从开始往下放两个字节以此类推。

2.其他成员变量则是要对齐,对齐数的整数倍(编译器默认的对齐数与该成员变量的大小取较小值)(VS的默认对齐数是8,Linux中gcc没有默认对齐数)

比如 在 struct S结构类型中,第二个结构体变量是int 类型,那么它的大小是 4 个字节 如果在VS中运行,那么VS默认的对齐数是 8, int 大小4 个字节,与默认对齐数8相比,取较小值,来作为它真正的对齐数。那么此时就取4来作为对齐数,因为其他成员变量要对齐,对齐数的整数倍,所以 第二个变量 要对齐 4的整数倍,所以这个时候 在第二个结构体变量 存放时,会从偏移量为4的倍数开始存放,此时偏移量为4的空间没有东西,那么int 类型会直接从4开始,往下存放4个字节。

最后一个 变量char c2,它的大小 是1 个字节,VS默认对齐数是8,那么 1 和8 取较小值作为真正对齐数, 所以选择1,那么char c2变量的存放需要对齐 1的倍数,我们就只需要把 char c2变量放在 1 的倍数的 偏移量处,只需要把char c2放在 int 变量 存放过的地址往下一个的地址就好了

此时总大小已经来到9个字节,可是还没有结束                                                                                 

3.结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对齐数中最大的)的
整数倍,我们知道,char c1 的对齐数是 1,int a的对齐数是 4,char c2的对齐数是1,那么结构体的总大小,必须是这些变量最大对齐数的整数倍,而这里最大的对齐数是 4,而目前9个字节的总大小并不是4的的整数倍,所以需要继续往下三个字节,让总大小变成12个字节,这样才是最终结构体的总大小,而没有使用到的字节空间则是被直接浪费掉了。                           

然后我们可以依照刚刚的办法,来计算 结构体变量 struct T

我们算出 8 就是全部字节,那么是 总大小吗? 我们再来看看 成员中的最大对齐数,是 int a 4, 

8是 4的倍数,那么8就是 struct T的总大小。 没有使用的空间则是被直接浪费了。

4.以下情况,

如果嵌套了结构体的情况,嵌套的结构体成员   struct T对齐的是自己的结构体成员中最⼤对⻬数的整数倍处,我们可以从上面就可以知道 struct T 自己的结构体成员中最大的结构体变量的对齐数是 4,所以struct T只需要 对齐 4,在4的倍数的偏移量开始存放空间就可以了。而struct 我们已经算出了它的总大小是 8个字节,所以我们只需要在4的偏移量处以此存放8个字节。结构体的整体大小依然是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍,short的 对齐数是 2, Struct T的对齐数是 4,int  i 的对齐数 是4,所以这里最大的对齐数是4,我们只需要比较我们计算的结构体大小,是否是结构体变量中最大对齐数4的倍数,如果是那么这就是最终大小,如果不是,那么需要往下补空间,补到最终字节大小是 对齐数的倍数就可以了,补的空间没有使用被直接浪费

所以我们可以算出,Struct D的结构体大小是 16个字节。我们可以通过代码结果来验证我们的思路。

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值