C++中的位元組對齊分析

來源:互聯網
上載者:User
文章目錄
  •   閱讀指引:     
  •  範例程式碼
  • 為什麼要位元組對齊
  • 編譯器對位元組對齊的一些規則
  • 結合編譯器原則分析樣本
  • 總結
  •   1.範例程式碼   
  •   2.為什麼要位元組對齊  
  •   3.編譯器對位元組對齊的一些規則    
  •           4. 結合編譯器分析樣本
  •   總結
  閱讀指引:     
  1.  範例程式碼
  2. 為什麼要位元組對齊
  3. 編譯器對位元組對齊的一些規則
  4. 結合編譯器原則分析樣本
  5. 總結
  1.範例程式碼   

  先看一下這段程式的運行結果。

範例程式碼

struct A
{
    int a;
    char b;
    short c;
};

struct B
{
    char a;
    int b;
    short c;
};

#pragma pack(2)
struct C
{
    char a;
    int b;
    short c;
};

#pragma pack(1)
struct D
{
    int a;
    char b;
    short c;
};

int _tmain(int argc, _TCHAR* argv[])
{

    cout << sizeof(A) << "   "<< sizeof B << "   "<< sizeof C << "   "<< sizeof D <<endl;
    return 0;
}  運行結果如下:8     12     8       7

  理論上來說,結構體A與B的大小應該都是一樣的,造成這種原因的就是位元組對齊引起來的。  

  2.為什麼要位元組對齊    為什麼呢?簡單點說:為了提高存取效率。位元組是記憶體空間分配的最小單位, 在程式中,我們定義的變數可以放在任何位置。其實不同架構 的CPU在訪問特定類型變數時是有規律的,比如有的CPU訪問int型變數時,會從偶數地址開始讀取的,int類型佔用4個位元組(windows平台)。 0X0000,0X0004,0X0008.....這樣只需要讀一次就可以讀出Int類型變數的值。相反地,則需要讀取二次,再把高低位元組相拼才能得到 int類型的值,這樣子看的話,存取效率當然提高了。  通常寫程式的時候,不需要考慮這些情況,編譯都會為我們考慮這些情況,除非針對那些特別架構的 CPU編程的時候的則需要考慮 。當然使用者也可以手工控制對齊。  3.編譯器對位元組對齊的一些規則    

  我從下面三條說明了編譯器對位元組處理的一些原則。當然除了一些特殊的編譯器在處理位元組對齊的方式也不一樣, 這些情況我未碰到過,就不作說明了。

  a. 關於資料類型自身的對齊值,不同類型會按不同的位元組來對齊。
類型 對齊值(位元組)
char 1
short 2
int 4
float 4
double 4
      b. 類、結構體的自身對齊位元組值。對於結構體類型與類對象的對齊原則:使用成員當中最大的對齊位元組來對齊。比如在Struct A中,int a的對齊位元組為4,比char,short都大,所以A的對齊位元組為4     c. 指定對齊位元組值。意思是指使用了宏 #pragma pack(n)來指定的對齊值

     d. 類、結構及成員的有效對齊位元組值。有效對齊值=min(類/結構體/成員的自身對齊位元組值,指定對齊位元組值)。   有效對齊值決定了資料的存放方 式,sizeof 運算子就是根據有效對齊值來導出成員大小的。簡單來說, 有效對齊其實就是要求資料成員存放的地址值能被有效對齊值整除,即:地址值%有效對齊值=0

    

          4. 結合編譯器分析樣本

          根據上面的原則,分析Struct A的size。結構體的成員記憶體配置是按照定義的順序來分析的。struct A
{    
   int a;    
   char b;    
   short c;
}       為了簡單起見, 我假設Struct A存取的起始地址為 0x0000 在沒有指定對齊值的情況下,分析步驟:     step 1: 根據第二條,首先為結構體選擇對齊值:選擇成員中最大的對齊值,即int a,對齊值為4
      
   step 2: 再根據第四條原則,決定有效對齊值:即然沒有手工指定對齊值,則使用預設的值:4(windows 32平台)   

    step 3: int a 的有效地址值=min(4,4),(因為0x0000%4=0),這樣a的地址就是從 0X0000~0x0003    

    step 4: char b 的有效對齊值=min(1,4),地址依次從0x0004 (因為Ox0004%1=0)開始,分配一個位元組,位址區段分配情況就是:0x0000~0x0004    

    step 5: short c 的有效對齊值=min(2,4),理論上說,分配的地址應該是連續的(從0x0005~0x00006),但是由於要求考慮到對齊的情況,所求要求位址區段 位移,這樣就從0x0006(Offset+1,因為0x0006%2=0)開始,分配2個位元組的地址0x0006~0x0007.

     
   目前為止,位址區段的分配情況就是:0x0000~0x0007這樣sizeof(A)的大小=0x0000~0x0007共8個位元組大小,同時,8%4=0保證了Struct A的位址區段與4成偶數倍。

     接下來分析Struct B的大小,同樣假設Struct B的起始地址為0x0000,分析步驟如下:

struct B
{
    char a;
    int b;
    short c;
}   step 1: 確實結構體B對齊值:選擇成員中最大的對齊值,即int a,對齊值為4
      
   step 2: 確定手工指定對齊值,使用預設的值:4(windows 32, VC6.0平台)   

   step 3: char a 的有效地址值=min(1,4),a的地址就是 0X0000(因為0x0000%1=0)   

   step 4: int b 的有效對齊值=min(4,4),地址依次從0x0004~0x0007 (因為Ox0004%1=0)開始,分配4個位元組,目前j位址區段分配情況就是:0x0000~0x0007    

    step 5: short c 的有效對齊值=min(2,4),c從0x0008~0x0009(因為0x0008%2=0)開始,位移2個位元組的地址0x0006~0x0007.
    
    至止,位址區段的分配情況就是:0x0000~0x0009共10個位元組,但是Struct B的對齊值為4,這就要求地址地段再位移2個位元組,這樣就是從0x0000~0x000B共12(因為12%4=0)個位元組大小。這樣,sizeof(B)=12

     
   

  再來使用Pragma手工更改了位元組對齊值的情況,先看看Struct C的定義:

#pragma pack(2)
struct C
{
    char a;
    int b;
    short c;
};

   在代碼中,手工指定了對齊值為2個位元組,分析步驟如下:

   step 1: 確定結構體C對齊值:選擇成員中最大的對齊值,即int a,對齊值為4
      
   step 2: 確定手工指定對齊值,使用手工指定的值:2

   step 3: char a 的有效地址值=min(1,2),(因為0x0000%2=0),這樣a的地址就是0x0000 

   step 4: int b 的有效對齊值=min(4,2),地址依次從0x0002~0x0005 (因為Ox0002%2=0)開始,分配4個位元組,目前位址區段分配情況就是:0x0000~0x0005    

    step 5: short c 的有效對齊值=min(2,2),由於要求考慮到對齊的情況,從0x0006(因為0x0006%2=0)開始,分配2個位元組的地址0x0006~0x0007

     
   目前為止,位址區段的分配情況就是:0x0000~0x0007共8個位元組,同時也保證了Struct C的對齊情況(2位元組對齊,pragma(2)),sizeof(C)=8

  請注意這種情況與Struct B的情況有區別,B的sizeof大小為12個位元組,C的sizeof大小為8個位元組。

   最後分析#pragma pack(1)這種情況,這種情況非常簡單,對齊值為1,因為1可以被任何資料整除,所以Struct D的成員變數存取順序是連續的,這樣就好辦了,sizeof(D)=sizeof(int)+sizeof(char)+sizeof(short)=4+1+2=7 (比如從0x0000~0x0006)

  總結

  在考慮位元組對齊時要細心,搞清楚幾個重要的概念,如類型自身對齊值,手工對齊值以及有效對齊值,有效對齊值決定了最後的存取方式,有效對齊值等於類型自身對齊值與手工對齊值中較小的一個。理解了這一點,對sizeof運算子對類型或都結構的運算也徹底明白了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.