對齊原則:
原則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; };