对齐原则:
原则1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,之后每一个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。数据结构
原则2:结构(或联合)的总体对齐规则:在数据成员完成各自对齐以后,结构(或联合)自己也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。性能
原则3:结构体做为成员:若是一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。大数据
默认对齐值:
Linux 默认#pragma pack(4)spa
window 默认#pragma pack(8)操作系统
注:能够经过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是指定的“对齐系数”。code
#pragma pack(1) struct AA { int a; //长度4 > 1 按1对齐;偏移量为0;存放位置区间[0,3] char b; //长度1 = 1 按1对齐;偏移量为4;存放位置区间[4] short c; //长度2 > 1 按1对齐;偏移量为5;存放位置区间[5,6] char d; //长度1 = 1 按1对齐;偏移量为6;存放位置区间[7] //总体存放在[0~7]位置区间中,共八个字节。 }; #pragma pack()
#pragma pack(2) struct AA { int a; //长度4 > 2 按2对齐;偏移量为0;存放位置区间[0,3] char b; //长度1 < 2 按1对齐;偏移量为4;存放位置区间[4] short c; //长度2 = 2 按2对齐;偏移量要提高到2的倍数6;存放位置区间[6,7] char d; //长度1 < 2 按1对齐;偏移量为7;存放位置区间[8];共九个字节 }; #pragma pack()
#pragma pack(4) struct AA { int a; //长度4 = 4 按4对齐;偏移量为0;存放位置区间[0,3] char b; //长度1 < 4 按1对齐;偏移量为4;存放位置区间[4] short c; //长度2 < 4 按2对齐;偏移量要提高到2的倍数6;存放位置区间[6,7] char d; //长度1 < 4 按1对齐;偏移量为7;存放位置区间[8];总大小为9 }; #pragma pack()
#pragma pack(8) struct AA { int a; //长度4 < 8 按4对齐;偏移量为0;存放位置区间[0,3] char b; //长度1 < 8 按1对齐;偏移量为4;存放位置区间[4] short c; //长度2 < 8 按2对齐;偏移量要提高到2的倍数6;存放位置区间[6,7] char d; //长度1 < 8 按1对齐;偏移量为7;存放位置区间[8],总大小为9 }; #pragma pack()
struct EE { int a; //长度4 < 8 按4对齐;偏移量为0;存放位置区间[0,3] char b; //长度1 < 8 按1对齐;偏移量为4;存放位置区间[4] short c; //长度2 < 8 按2对齐;偏移量由5提高到6;存放位置区间[6,7] //结构体内部最大元素为int,因为偏移量为8恰好是4的整数倍,因此从8开始存放接下来的struct FF struct FF { int a1; //长度4 < 8 按4对齐;偏移量为8;存放位置区间[8,11] char b1; //长度1 < 8 按1对齐;偏移量为12;存放位置区间[12] short c1; //长度2 < 8 按2对齐;偏移量为13,提高到2的倍数14;存放位置区间[14,15] char d1; //长度1 < 8 按1对齐;偏移量为16;存放位置区间[16] }; //总体对齐系数 = min((max(int,short,char), 8) = 4,将内存大小由17补齐到4的整数倍20 char d; //长度1 < 8 按1对齐;偏移量为21;存放位置区间[21] //总体对齐系数 = min((max(int,short,char), 8) = 4,将内存大小由21补齐到4的整数倍24 };
struct B { char e[2]; //长度1 < 8 按2对齐;偏移量为0;存放位置区间[0,1] short h; //长度2 < 8 按2对齐;偏移量为2;存放位置区间[2,3] //结构体内部最大元素为double,偏移量为4,提高到8,因此从8开始存放接下来的struct A struct A { int a; //长度4 < 8 按4对齐;偏移量为8;存放位置区间[8,11] double b; //长度8 = 8 按8对齐;偏移量为12,提高到16;存放位置区间16,23] float c; //长度4 < 8,按4对齐;偏移量为24,存放位置区间[24,27] }; //总体对齐系数 = min((max(int,double,float), 8) = 8,将内存大小由28补齐到8的整数倍32 };
一、平台缘由(移植缘由):不是全部的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,不然抛出硬件异常。图片
二、性能缘由:数据结构(尤为是栈)应该尽量地在天然边界上对齐。缘由在于,为了访问未对齐的内存,处理器须要做两次内存访问;而对齐的内存访问仅须要一次访问。内存
更简单的说明下:如图io
首先,cpu的访问粒度为4,也就是一次性能够读取内存中的四个字节内容;当咱们不采用内存对齐策略,若是须要访问A中的b元素,cpu须要先取出0~3四个字节的内容,发现没有读取完,还须要再次读取,一共须要进行两次访问内存的操做;而有了内存对齐,参考左图,可一次性取出4~7四个字节的元素也便是b,这样就只须要进行一次访问内存的操做。因此操做系统这样作的缘由也就是所谓的拿空间换时间,提升效率。编译
struct A { char a; int b; char c; }; struct B { char a; char c; int b; };