字节对齐
编译过程中c++编译器为了提高存取速度,设置了在存储格式上的字节对齐。
------------------------------------------------
1.为什么设置字节对齐能提高存取速度
------------------------------------------------
答:主要是因为现代计算机都使用了Cache。
Cache可以看成一些可以用非常快的速度进行访问的临时内存。但是Cache的容量不大,比如一般一级Cache只有几K到几十K,二级Cache只有几百K到几M.这个同数G的内存相比,是比较小的。
但是CPU访问内存非常慢,所以硬件会将平时经常使用的内容存放到Cache里面。Cache是通过一些Cache Line来组织的,每一条Cache Line一般包含16个字节,32个字节或64个字节等。 比如某个计算机一级Cache的Cache Line长度是32个字节,那么每段Cache Line总是会包含32个字节对齐的一段内存。
现在有一个4字节的整数,如果它的地址不是4字节对齐的,那么就有可能访问它的时候,需要使用两条Cache Line,这增加了总线通讯量,而且增加了对Cache的使用量,而且使用的数据没有在Cache里面(这时需要将数据从内存调入Cache,会非常慢)的机会会增加,这些都降低了程序的速度。
------------------------------------------------
2.字节对齐过程分析
------------------------------------------------
答:在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0 32位系统)
类型 对齐方式(变量存放的起始地址相对于结构的其实地址的偏移量)
char 偏移量必须为sizeof(char)即1的倍数
int 偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
short 偏移量必须为sizeof(short)即2的倍数
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节vc会自动填充。同时vc为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
以你的情况为例:
struct Mystruct1
{
int a;
bool b;
bool c;
}
为上面的结构分配空间的时候,vc根据成员变量出现的顺序和对齐方式,先为第一个成员a分配空间,其起始地址跟结构的起始地址相同(偏移量为0,刚好为sizeof(int)的倍数),该成员变量占用sizeof(int)=4个字节;接下来为第二个成员b分配空间,这时下一个可以分配的地址相对于结构的起始地址的偏移量为4,是size(bool)=1的倍数(注意:sizeof(BOOL)=4;sizeof(bool)=1),所以把b存在在偏移量为4的地方满足对齐方式,该成员变量占用1个字节;接下来为第三个成员c分配空间,这时下一个可以分配的地址相对于结构的其实地址的偏移量为5,是sizeof(bool)的倍数,所以c存放在偏移量为5的地方满足对齐方式。
这时,所有的成员变量都分配的空间,总空间的大小为4+1+1=6,不是结构的字节边界数(即结构中占用最大空间的类型所占用的字节sizeof(int)=4)的倍数,所以需要填充2个字节,以满足结构的大小为sizeof(int)=4的倍数。这时结构占用的内存大小为4+1+1+2=8。
同样的道理
struct Mystruct1
{
bool a;
int b;
bool c;
}
的分配方式为:
第一个成员变量a占用1个字节,相对于结构的起始地址偏移量为0,满足对齐方式;第二个成员变量b占用4个字节,下一个可用的地址的偏移量为1,不是4的倍数,需要补足3个字节才能使偏移量为4(满足对齐方式),因此vc自动填充3个字节,b存放在偏移量为4的地址上,它占用4个字节。第三个成员变量c占用1个字节,下一个可用的地址为8(满足对齐方式),所以存放在偏移量为8的地址上;所有成员都分配了空间4+4+1=9,不是结构的字节边界数(sizeof(int))的倍数,所以填充三个字节以满足结构的大小为sizeof(int)的倍数,这样总的空间大小为4+4+4=12。