为什么字节对齐:
体系结构的对齐和不对齐,是在时间和空间上的一个权衡。对齐节省了时间。假设一个体系结构的字长为w,那么它同时就假设了在这种体系结构上对宽度为w的数据的处理最频繁也是最重要的。它的设计也是从优先提高对w位数据操作的效率来考虑的。
对齐准则:
1数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。
2结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.
例子:
typedef struct bb
{
int id; //[0]....[3]
double weight; //[8].....[15] 原则1
float height; //[16]..[19],总长要为8的整数倍,补齐[20]...[23] 原则3
}BB;
typedef struct aa
{
char name[2]; //[0],[1]
int id; //[4]...[7] 原则1
double score; //[8]....[15]
short grade; //[16],[17]
BB b; //[24]......[47] 原则2
}AA;
int main()
{
AA a;
cout<
return 0;
}
结果:48 24
#pragma pack():
在代码前加一句#pragma pack(1),你会很高兴的发现,上面的代码输出为
32 16
bb是4+8+4=16,aa是2+4+8+2+16=32;
#pragma pack(1),告诉编译器,所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则.
-----------------------------以下来自百度百科的整理-------------------------
字节对齐:
现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
作用和原因:
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。、
四个重要的基本概念
1.基本数据类型自身的对齐值:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float类型,其自身对齐值为4,对于double型,其自身对齐值为8,单位字节。
2.结构体(共用体)或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员(基本数据类型)、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
对齐规则
有效对齐值N是最终用来决定数据存放地址方式的值,最重要。
数据(数据成员(基本数据类型)、结构体(共用体)和类)的有效对齐值N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0"。
结构体中的成员变量都是按定义的先后顺序来排放。第一个数据变量的起始地址就是数据结构的起始地址。之后的成员变量按其有效对齐值存放。
结构体的成员变量按照自身有效对齐值对齐排放,结构体本身也要根据自身的有效对齐值存放。
总结:
其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被有效对齐值的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量都是成员有效对齐值的整数倍,如有需要编译器会在成员之间加上填充字节。
3) 结构体的总大小为结构体有效对齐值大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
网友评论