結構是如何對齊的?

  對於結構體,編譯器會自動進行成員變量的對齊,以提高運算效率。結構對齊爲什麼能提高效率呢?原因在於,爲了訪問未對齊的內存,處理器需要作兩次內存訪問,而對齊的內存訪問僅需要一次訪問。編譯器爲結構體的每一個成員按照按其自然對界(對字,雙字,和四字來說,自然邊界分別是偶數地址,可以被4整除的地址,和可以被8整除的地址。)條件進行分配空間。

默認情況下,結構採用自然對界(natural alignment)的對齊方式,即按結構體的成員中size最大的成員對齊。舉例如下:

struct aligntExample
{
    char a;
    short b;
    char c;
};
在上述結構體中,size最大的是short,其長度爲2字節,因而結構體中的char成員a、c都以2爲單位對齊,sizeof(aligntExample)的結果等於6。

默認的對齊方式可以通過#pragma  pack(n)來自定義對齊方式,其中"n"表示採用多少個字節進行對齊。

 

win32中約定的對齊方式爲如下所示:
數據類型     對齊方式      
char    按一字節的倍數對齊      
short    按二字節的倍數對齊      
int/long    按四字節的倍數對齊      
float    按四字節的倍數對齊      
double    按八字節的倍數對齊      
結構體    按結構中成員最大的對齊方式對齊     

前面四種數據類型的對齊是指該成員一定要放在自身長度的整數倍數的地址上,而結構體的對齊是指結構的總大小一定要是結構的倍數。

所以,結構的對齊問題包含了2個方面:一是結構成員的對齊,一是整個結構體大小的對齊。

#pargma pack(n)施加於結構上以後,我們該怎麼計算結構的大小呢?

計算方法如下:
   結構的數據成員第一個一定放在偏移爲0的地方,後續每個數據成員的對齊,按照這個數據成員自身長度和要求的對齊長度n中比較小的那個進行計算,而最後整個結構的對齊,則按照結構中成員基本類型長度最大的和要求的對其長度n中比較小的那個進行比較計算。舉例如下:
#pargma pack(4)
typedef struct alignment
{
    long A1;
    char B2;
    short C3;
    char D4;
    long E5;
    long F6;
    char G7;
}ALIGNMENT;
#pargma pack()

1)第一個成員A1爲long,自身長度爲4,放在偏移爲0的地址,佔用4個字節,地址空間爲0~3,下一個地址爲4;
2)第二個成員B2爲char,自身長度爲1,必須放在min(1,n) = 1的倍數地址上,當前地址爲4,符合,所以放在偏移爲4的地址上,佔用一個字節,地址空間爲4,下一地址爲5;
3)第三個成員C3爲short,自身長度爲2,必須放在min(2,n) = 2的倍數地址上,當前地址爲5,不符合,所以C3向後移動放在偏移爲6的地址上,地址5空出,佔用兩個字節,地址空間爲6~7,下一地址爲8;
4)第四個成員D4爲char,自身長度爲1,必須放在min(1,n) = 1的倍數地址上,當前地址爲8,符合,所以D4放在偏移爲9的地址上,佔用一個字節,地址空間爲8,下一地址爲9;
5)第五個成員E5爲long,自身長度爲4,必須放在min(4,n) = 4的倍數地址上,當前地址爲9,不符合,所以E5放在偏移爲12的地址上,佔用4個字節,地址空間爲12~15(9~11空出),下一地址爲16;
6)第六個成員F6爲long,自身長度爲4,必須放在min(4,n) = 4的倍數地址上,當前地址爲16,符合,所以F6放在偏移爲16的地址上,佔用4個字節,地址空間爲16~19,下一地址爲20;
7)第七個成員G7爲char,自身長度爲1,必須放在min(1,n) = 1的倍數地址上,當前地址爲20,符合,所以G7放在偏移爲20的地址上,佔用1個字節,地址空間爲20,下一地址爲21;

最後,整個結構的對齊(即結構的大小),必須是min(結構中成員基本類型長度最大的,n) = 4的倍數,現在結構佔用了0~20的空間,佔用21個字節,所以補3個字節,佔用21~23,總共24個字節,結構之後的變量佔用的地址從24開始,保證後續變量在整數邊界處。

最終結果:sizeof(ALIGNMENT) = 24。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章