[转自:http://ieoqmdce.blog.163.com/blog/static/389399542009636836665/]
在编程中,我们常常会碰到字节对齐这方面的问题,偶就曾经碰到过。公司要求我把一段在Linux下的源代码改为运行在Windows下,偶修正了所有的语法错误,可是出来的数据总是多出几个字节,一样的代码,为什么会多出几个字节???最后查看了其头结构,才知道罪魁祸首是字节对齐方式和Linux的不一样,在Linux下其是按2字节对齐,可是在VC++下默认是按8字节对齐,知道这,然后改正,果然一切OK!
字节对齐在编程中是最容易被忽略而又很难查找的问题,为什么需要字节对齐???这要从数据在内存中的存放说起,在内存中,数据的存放是有一定限制和规定的,比如double基本数据在内存的地址是8的倍数,这样做有什么好处,我想最大的好处应该是存取效率。试想,如果CPU每次可以取出8字节的数据,那么存取double类型的数据只需要访问一次内存就可以完成,但是如果对齐方式不是8,那么如果恰巧数据是横跨在两个符合对齐要求的8字节内存快上,这就需要访问内存两次。当然,现在Intel CPU可以处理任何对齐方式的数据,但有些类型的CPU在碰到没有对齐的数据时将会出错!
那么怎样来计算Struct结构的大小呢???以VC++6.0为例,采用默认设置,看看下面的结构,其Size是多少???
struct tagTest01
{
char chOne;
short shOne;
int iOne;
};
首先,chOne的基本数据类型为char,Size为1,占用1字节;shOne的基本数据类型为short,Size为2字节,所以其地址应该从2的整数倍开始,因此前面填充一个字节,这样它的偏移地址为2而不是1;iOne的基本数据类型为int,Size为4,而这里的偏移地址恰巧也是4,不用填充。因为已经是4的整数倍。好了,现在应该很明确,此结构的Size应为8。
然后,我们把上述结构中的数据成员的顺序调换一下,再看看如下的结构它的Size是否有变化:
struct tagTest02
{
int iOne;
short shOne;
char chOne;
};
可能按照上面的分析,我们会理所当然地认为上述结构的Size为7,如果真是这样的话,如果把此结构当着一个数组的一个元素的,他们也应该是要按所要求的字节对齐方式对齐的,好了,这里问题就出现了,如果定义了这样的数组struct tagTest02 arrOne[10];arrOne[0]的首地址为0,那么arrOne[1]的地址是多少呢,7 ???这显然已经不是我们默认设置的8字节对齐方式了,所以在chOne后面还是要填充一个字节,这样才满足8字节的对齐要求。到这里应该明白了吧。
好了,上面采用的是默认的8字节对齐方式,如果是1,2,4呢,我们怎样来计算其Size呢,这里本人经过实际的经验总结这几条规则:
假设你要对齐的字节数为N,基本数据类型的Size为S,那么当S小于等于N时,采用S对齐方式来对齐,如果S大于N时则采用N来对齐,比如N为2,那么对于int型的数据其对齐方式还是2字节而不是4了,知道了这一点,我们就很容易计算出任何一个struct的size了。
如果有兴趣的可以计算一下下面的结构的Size是多少(对齐方式N分别为1,2,4,8)?
#pragma pack(N)
struct tagTest
{
short shTest;
char chOne;
int iTest;
char chTow;
double dTest;
};
#pragma pack()
注意:当N不是2的倍数的时候,将采用默认设置的字节对齐方式。