结构体-------内存对齐深度剖析

1.结构体的对齐现象的存在及其解释

通过这个例子我们就可以看到a的大小是一个字节,b的大小是4个字节,c的大小是1个字节,最后的输出结构体的大小却是12个字节,出现这个情况的原因就是结构体的内存对齐现象,下面我们首先来看一下结构体的对齐规则:

下面我们利用结构体的对齐规则解释一下上面的问题:

上边的这张图就是对应的结构体里面定义的变量内存对齐的具体情况,我们依次了解一下

(1)第一个结构体变量从对齐到偏移量为0的地址处,a的大小是一个字节,所以最后的对其结果就是图里面的黄色方块;

(2)其他变量的对齐数是变量的自身大小和编译器的默认对齐数的较小值,默认对齐数是8(编译器自身决定的,我们知道就好),b的本身大小是4,两者的较小值就是4,所以这个变量应该从4的最小倍数,也就是4的地方开始对齐,自身是4字节,所以变量b的内存对齐情况就是蓝色的4567方块;

(3)变量c遵循着同样的规则,自身的大小是1,编译器的默认对齐数是4,所以两者里面的较小值就是1,对齐到1的最小倍数,因为任何的一个数字都是1的最小倍数,所以我们可以直接从8这个黑色的方块开始,1个字节的大小;

(4)这个时候虽然已经完成了,但是结构体的大小却不是9,因为还有最后的一句规则,结构体的整体大小就是最大对齐数的整数倍,这个里面的最大对齐数指的是变量的对齐数的最大值,我们在前面已经计算过,变量a,b,c分别是1,4,1,里面的最大值就是4,因为结构体的本身已经占据了9个字节,这个时候4的2倍8就已经太小了,所以我们结构体的总体大小应该是4*3=12的字节。

2.嵌套结构体大小的计算

(1)对于这样的一个嵌套的结构体,我们首先要做的就收搞清楚嵌套的情况,分别计算然后进行叠加;

(2)这个里面显然是S2结构体嵌套S结构体,我们首先是可以计算出来S的结构体的大小的,利用上面讲述的规则,a是8个大小,和默认对齐数相等,b这个字符是1个大小,任何数都是他的倍数,所以直接往下继续排列就可以了;c是一个整型,应该偏移4*3=12的位置处,所以从12开始占据4个字节就可以了,总的来看,8,1,4里面的最小值就是8,结构体的大小8*2=16就是我们的结构体S的大小,下面是其具体的排布情况;

(3)接下来我们应该分析S2这个结构体了,这个时候S2里面的第一个变量是1个字节,第二个就是一个结构体变量,这个变量的大小是16,这个我们已经知道了,但是这个变量应该从什么地方对其呢,记住是结构体成员的对打对齐数的整数倍(这个结构体成员指的是S里面的结构体成员,显然是8,所以偏移量应该是8),因为大小是16字节,所以我们直接占据16字节,这个里面肯定有字节的浪费,但是我们不去关心,因为这个是S结构体内部的事情,我们只关注它的大小(占据的空间),S2里面的的第三个变量double类型的,从8的倍数24的偏移量开始,占据8个字节,这个时候整个结构体的大小应该是所有的变量的最大对齐数的整数倍,显然S2,S里面的5个变量,最大的就是double类型的,占据8个字节,结构体的大小就是8*4=32字节。

3.内存对齐的原因

这个里面既有平台的原因,也有性能的原因

这个对齐现象总体概括就是拿时间换空间,怎么理解呢,上面列举了对齐和不对齐的2种情况,蓝色的是char类型,黄色的是int类型,如果不对齐,直接int类型往后占据4字节就可以了,对齐的话就要从4的倍数开始,就要浪费3个字节;在32位机器,一次读取4字节,对于这个int类型的数据,如果不对齐,我们需要读取2次才能得到int类型的数据,如果存在对齐,读取一次就可以拿到int类型的这个数据了,这样就节省了时间,所以我们称之为拿时间换空间;

我们尽量把这些占据空间小的数据类型,例如char类型,我们把这些类型放在一起,就可以顺序排放,因为所有的数字都是1的倍数,这样做相对而言可以减少字节的浪费;

4.修改默认对齐数

我们使用#pragna pack(1)就可以修改默认对齐数为1,效果如下:

我们设置的默认对齐数不能随意设置,一般都是2的次方倍;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值