c中结构体数据对齐问题

百般思念 提交于 2020-01-10 14:07:34

 

1.为什么需要数据对齐

提升CPU读取数据的效率。CPU每次都是从以4字节(32位CPU)或是8字节(64位CPU)的整数倍的内存地址中读进数据的(例如32位的只能0x00000004、0x00000008这种地址一次读4字节的数据)。如果数据不对齐,例如一个int类型放在0x00000004、0x00000008这两个内存地址中间,CPU就会多次读取,如果把整形对齐存放在0x00000008就可以一次读取出来。

2.分析(编译器:Dev 电脑:64位)

我们用创建结构体然后用sizeof打印出结构体大小方式来验证数据对齐方式

正式开始,定义一个char和int,如果不对齐sizeof的结果应该是5,看结果

结果是8,将char于int类型补齐,即对char补齐了3个字节。结果是(1+3)+4=8.(注:所有计算试中斜体加粗数据为补齐用)

如果再往后面添加一个数据呢?

依旧会将最后一个char进行数据对齐,结果为(1+3)+4+(1+3)=12

我们将c换到中间去,结果是否还是12呢?

结果变成了8,原因是a和c所需的空间为2,不需要各自补齐3个空间。结果为((1+1)+2)+4=8

那对字符数组呢?

把a[5]直接拆开成5个char类型即可,结果为((1+1+1+1+1)+3)+4=12.

可以做一个小结:可以发现,结构体sizeof大小总为一个结构体中数据占用空间最大的那个变量的倍数,上面的例子就可以发现如果最大的变量类型是int,那么sizeof一定是4的倍数,两个相连的数据如果拼凑起来不是4的倍数就需要进行数据对齐,计算时不要跳过中间某个变量与后一个变量进行相加计算。至于包含的数组,拆开来算,就像上面那个例子,sizeof不能是字符数组a[5]的5的倍数,依旧还是按照单个变量的最大值来补齐。

复杂化一点,结构体里面再包含一个结构体呢?

好像没有什么悬念,struct text2为8字节,那text1结果为((5+4)+7)+8=24

在text2中再加一个char会怎样呢,那是不是与16对齐呢,那结果会不会是((5+4)+7)+16=32呢?

猜对了!

那我们把text1中b移到member下面,那结果会不会按照16补齐,是(5+11)+16+(4+12)=48呢?

 诶?为什么是32,结果不应该按照16补齐为48吗?还记得上面我们怎么对待数组的吗,对!拆开它!,对待结构体中的结构体也要这样,拆开它!把struct text2中所有的数据移到tex1中计算就好了,所以很明显最大的变量大小为8,结果为(5+3)+8+(1+4+3)=24,诶?好像不是32啊,怎么回事!看打印,text2=16,嗷,text2已经数据对齐了,那我们就算错了,结果应该是(5+3)+16+(4+4)=32。小结:所以当有结构体包含结构体应该怎么算大小呢,找出所有包含结构体中变量最大的那个一个,数据补齐就按照他的空间大小补齐,然后依次计算出包含的结构体大小,再对其他变量进行计算。

 

 3.结尾

计算结构体的大小,先要找到里面空间最大的变量,再从头到尾第一个变量到最后一个变量空间依次相加并对不足进行补齐。

由此可见,如果结构体里面的数据变量按照空间从大到小或者从小到大依次排列,可以节省空间,不过,也不怎么在乎了,浪费的空间应该也不咋大。

当然,默认是进行对齐处理的,如果接触过通信协议的代码,构造报文的结构后面基本上都有这么一句话,__attribute__ ((packed)),这个是将这个结构按照实际字符来存储,不做对齐处理,这样有什么好处呢,通过指定的偏移量就可以快速获取指定的参数值,巨方便,这里就不再过多说明了,就提一下。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!