结构体数据对齐方法的研究
2017-05-19王若
王若
摘要:内存地址对齐,是一种在计算机内存中排列数据、访问数据的一种方式。当今的计算机在计算机内存中读写数据时都是按字(word)大小块来进行操作的。基本类型数据对齐就是数据在内存中的偏移地址必须等于一个字(word)的倍数,按这种存储数据的方式,可以提升系统在读取数据时的性能。有时候为了对齐数据,可能必须在上一个数据结束和下一个数据开始的地方插入一些没有用处字节,这就是结构体数据对齐。
关键词:结构;数据
一、假设计算机的字大小为4个字节,因此变量在内存中的首地址都是满足4地址对齐,CPU只能对4的倍数的地址进行读取,而每次能读取4个字节大小的数据
假设有一个整型的数据a的首地址不是4的倍数,因此想读取a的数据,CPU要进行两次内存读取,而且还要对两次读取的数据进行处理才能得到a的数据,而一个程序的瓶颈往往不是CPU的速度,而是取決于内存的带宽,因为CPU得处理速度要远大于从内存中读取数据的速度,因此减少对内存空间的访问是提高程序性能的关键[1]。从上例可以看出,采取内存地址对齐策略是提高程序性能的关键。
二、结构体默认的规则
本文所述的环境均是在32位编译器的编译环境中,一般编译器默认对齐方式是4字节。
总结结构体的数据对齐方式满足条件:
1、结构体变量的首地址能够被其最宽基本类型成员的大小所整除。2、结构体每个成员相对于结构体首地址的偏移量(offset)都是成员自身大小的整数倍,如有需要编译器会在成员之间加上填充字节。3、结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
三、手动对齐方式
如果编译器自动实现结构体对齐,我们就称为自动对齐,与之相反,使用#pragma进行对齐的就是手动对齐。
#pragma备用告诉编译器,程序员自己希望的对齐方式。比如,虽然编译器的默认对齐方式是4,但是如果我们不希望按照4对齐,而是希望是8,这个时候就必须使用#pragma进行手动对齐了。
常用的设置手动对齐的命令有两种:第一种是#pragmapack(),这种就是设置编译器1字节对齐,不过也可以认为是设置为不对齐或者取消对齐;第二种是
#pragmapack(4),这个括号中的数字表示希望以多少字节进行对齐。
我们需要#prgamapack(n)开头,以#pragmapack()结尾,定义一个区间,这个区间内的对齐参数就是n。
举例说明
(一)自动对齐方式或者是默认4字节对齐
分析代码:根据基本数据类型对齐规则可知,c(字节),i(4字节),d(8字节),b(2字节)。是不是结果就是1+4+8+2呢?很明显不是,c是首元素,不需要对齐,但是后面的就需要对齐了,i是4字节,但是它的起始偏移量只有1字节,不能整除4,因此就在c后面再加3个字节,当遇到d时,由于之前的偏移量就是8,所以不需要偏移,在b之前有16字节,这时也不需要偏移就是直接加上2。所以最后结果就是1+3+4+8+2=20,对不对呢?其实是不对的,因为18不是默认对齐4的整数倍,还需要在后面补充2字节。一共就是20字节。
分析:该结果就是24字节,分析同上,但是在最后一步不一样,对齐是8字节,所以在b后面还需要添加6字节。最终结果就是24.
四、结语
需要字节对齐的根本原因在于CPU访问数据的效率问题。因为计算机可以处理数据位数都是确定的,这时候就说明它一次性只能处理确定位数的数据,但是当认为造成该数据不在计算机一次性可访问的范围内的时候,计算机就会按照一定的优化方法来处理,这样是更加方便和快捷的处理数据。也就是强制的要求一来简化了处理器与内存之间传输系统的设计,二来可以提升读取数据的速度。
参考文献
[1] 陈荣,蔡志勇,胡保安. 基于嵌入式操作系统VxWorks数据采集系统软件设计[J]. 科技广场,2005,(06):82-84.