結構體在內存中的對齊規則

轉載出處:http://blog.csdn.net/liukun321/article/details/6974282
一個結構體變量定義完之後,其在內存中的存儲並不等於其所包含元素的寬度之和。

例一:

                                  #include <iostream>

                                  using namespace std;

                                     struct X

                                     {

                                          char a;

                                          int b;

                                          double c;

                                     }S1;



                                 void main()

                                {

                                     cout << sizeof(S1) << endl;

                                     cout << sizeof(S1.a) << endl;

                                     cout << sizeof(S1.b) << endl;

                                     cout << sizeof(S1.c) << endl;

                                }

 比如例一中的結構體變量S1定義之後,經測試,會發現sizeof(S1)= 16,其值不等於sizeof(S1.a) = 1、sizeof(S1.b) = 4和 sizeof(S1.c) = 8三者之和,這裏面就存在存儲對齊問題。

原則一:結構體中元素是按照定義順序一個一個放到內存中去的,但並不是緊密排列的。從結構體存儲的首地址開始,每一個元素放置到內存中時,它都會認爲內存是以它自己的大小來劃分的,因此元素放置的位置一定會在自己寬度的整數倍上開始(以結構體變量首地址爲0計算)。

比如此例,首先系統會將字符型變量a存入第0個字節(相對地址,指內存開闢的首地址);然後在存放整形變量b時,會以4個字節爲單位進行存儲,由於第一個四字節模塊已有數據,因此它會存入第二個四字節模塊,也就是存入到4~8字節;同理,存放雙精度實型變量c時,由於其寬度爲8,其存放時會以8個字節爲單位存儲,也就是會找到第一個空的且是8的整數倍的位置開始存儲,此例中,此例中,由於頭一個8字節模塊已被佔用,所以將c存入第二個8字節模塊。整體存儲示意圖如圖1所示。

考慮另外一個實例。

例二:

                                       struct X

                                       {

                                            char a;

                                            double b;

                                            int c;

                                        }S2;

在例二中僅僅是將double型的變量和int型的變量互換了位置。測試程序不變,測試結果卻截然不同,sizeof(S2)=24,不同於我們按照原則一計算出的8+8+4=20,這就引出了我們的第二原則。





原則二:在經過第一原則分析後,檢查計算出的存儲單元是否爲所有元素中最寬的元素的長度的整數倍,是,則結束;若不是,則補齊爲它的整數倍。

例二中,我們分析完後的存儲長度爲20字節,不是最寬元素長度8的整數倍,因此將它補齊到8的整數倍,也就是24。這樣就沒問題了。其存儲示意圖如圖2所示。



掌握了這兩個原則,就能夠分析所有數據存儲對齊問題了。再來看幾個例子,應用以上兩個原則來判斷。

例三:

                                          struct X

                                          { 

                                               double a;

                                               char b;

                                               int c;     

                                          }S3;

首先根據原則一來分析。按照定義的順序,先存儲double型的a,存儲在第0~7個字節;其次是char型的b,存儲在第8個字節;接下來是int型的c,順序檢查後發現前面三個四字節模塊都被佔用,因此存儲在第4個四字節模塊,也就是第12~15字節。按照第一原則分析得到16個字節,16正好是最寬元素a的寬度8的整數倍,因此結構體變量S3所佔存儲空間就是16個字節。存儲結構如圖3所示。

例四:

                                          struct X

                                          { 

                                               double a;

                                               char b;

                                               int c;

                                               char d;   

                                          }S4;



仍然首先按照第一原則分析,得到的字節數爲8+4+4+1=17;再按照第二原則補齊,則結構體變量S4所佔存儲空間爲24。存儲結構如圖4所示:

例五:

                                          struct X

                                          { 

                                               double a;

                                               char b;

                                               int c;

                                               char d;

                                               int e; 

                                           }S5;

同樣結合原則一和原則二分析,可知在S4的基礎上在結構體內部變量定義最後加入一個int型變量後,結構體所佔空間並未增加,仍爲24。存儲結構示意圖如圖5所示。

例六:

如果將例五中加入的變量e放到第一個定義的位置,則情況就不同了。結構體所佔存儲空間會變爲32。其存儲結構示意圖如圖6所示。

                                          struct X

                                          { 

                                              int e;

                                              double a;

                                              char b;

                                              int c;

                                              char d;

                                          }S6;



補充:前面所介紹的都是元素爲基本數據類型的結構體,那麼含有指針、數組或是其它結構體變量或聯合體變量時該如何呢?

1.包含指針類型的情況。只要記住指針本身所佔的存儲空間是4個字節就行了,而不必看它是指向什麼類型的指針。

例七:

                struct X              struct Y               struct Z

                {                     {                      {     

                   char *a;              int *b;                 double *c;

                };                     };                     };

經測試,可知sizeof(X)、sizeof(Y)和sizeof(Z)的值都爲4。

2.含有構造數據類型(數組、結構體和聯合體)的情況。首先要明確的是計算存儲空間時要把構造體看作一個整體來爲其開闢存儲空間;其次要明確的是在最後補齊時是按照所有元素中的基本數據類型元素的最長寬度來補齊的,也就是說雖然要把構造體看作整體,但在補齊的時候並不會按照所含結構體所佔存儲空間的長度來補齊的(即使它可能是最長的)。

例八:

                                  struct X

                                 {

                                      char a;

                                      int b;

                                      double c;

                                  };

                                  struct Y

                                  {

                                       char a;

                                       X b;

                                   };

經測試,可知sizeof(X)爲16,sizeof(Y)爲24。即計算Y的存儲長度時,在存放第二個元素b時的初始位置是在double型的長度8的整數倍處,而非16的整數倍處,即系統爲b所分配的存儲空間是第8~23個字節。

如果將Y的兩個元素char型的a和X型的b調換定義順序,則系統爲b分配的存儲位置是第0~15個字節,爲a分配的是第16個字節,加起來一共17個字節,不是最長基本類型double所佔寬度8的整數倍,因此要補齊到8的整數倍,即24。測試後可得sizeof(Y)的值爲24。

由於結構體所佔空間與其內部元素的類型有關,而且與不同類型元素的排列有關,因此在定義結構體時,在元素類型及數量確定之後,我們還應該注意一下其內部元素的定義順序。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章