(轉)操作系統學習(五)——64位系統與32位系統在數據結構占用上的區別

原文地址:http://blog.csdn.net/chenhanzhun/article/details/39641489

前言

在計算機中數據存儲和傳輸以位(bit)為單位,每8個位bit組成1個字節(Byte)。32位計算機的字長為32位,即4個字節;對應的,64位計算機的字長為64位,即8個字節。計算機系統對基本類型數據在內存中存放的位置有限制,要求這些數據的起始地址的值是某個數k的倍數,這就是所謂的內存對齊,而這個k則被稱為該數據類型的對齊模數(alignment modulus)。

結構的存儲分配

編譯器按照結構體成員列表的順序為每個成員分配內存,當存儲成員時需要滿足正確地邊界對齊要求時,成員之間可能出現用于填充地額外內存空間。32位系統每次分配字節數最多為4個字節,64位系統分配字節數最多為8個字節。
以下圖表是在不同系統中基本類型數據內存大小和默認對齊模數:



注:此外指針所占內存的長度由系統決定,在32位系統下為32位(即4個字節),64位系統下則為64位(即8個字節).

沒有#pragma pack宏的對齊

對齊規則 :

  1. 結構體的起始存儲位置必須是能夠被該結構體中最大的數據類型所整除。
  2. 每個數據成員存儲的起始位置是自身模數的整數倍(比如int在32位機為4字節,則int型成員要從4的整數倍地址開始存儲)。
  3. 結構體總大小(也就是sizeof的結果),必須是該結構體成員中最大的對齊模數的整數倍。若不滿足,會根據需要自動填充空缺的字節。
  4. 結構體包含另一個結構體成員,則被包含的結構體成員要從其原始結構體內部最大對齊模數的整數倍地址開始存儲。(比如struct a里存有struct b,b里有char,int,double等元素,那b應該從8的整數倍開始存儲。)
  5. 結構體包含數組成員,比如char a[3],它的對齊方式和分別寫3個char是一樣的,也就是說它還是按一個字節對齊。如果寫:typedef char Array[3],Array這種類型的對齊方式還是按一個字節對齊,而不是按它的長度3對齊。
  6. 結構體包含共用體成員,則該共用體成員要從其原始共用體內部最大對齊模數的整數倍地址開始存儲。

現在給出一個結構體,我們針對win-32和Linux-32進行分析,例1:

struct MyStruct 
{ 
  char a; 
  int b; 
  long double c; 
}; 

解答

win-32位系統下

由上圖可知該結構體的最大對齊模數為sizeof(long double)=8;假設MyStruct從地址空間0x0000開始存放。char為1個字節,所以a存放于0x0000中;int為4個字節,根據規則,b存儲的起始地址必須為其對齊模數4的整數倍,所以a后面自動填充空缺字節空間0x0001-0x0003,因此b存放于0x0004-0x0007中。long double是8個字節,由于32位系統每次最多分配4個字節,則首先分配0x0008-0x000B,由于不夠存儲空間,則繼續分配0x000C-0x000F,所以c存儲在0x0008-0x000F中,由于此時總存儲空間為4+4+8=16;則16滿足最大對齊模數sizeof(long double)=8的整數倍;因此,sizeof(MyStruct)=16個字節。

Linux-32位系統下:

由上圖可知該結構體的最大對齊模數為4;假設MyStruct從地址空間0x0000開始存放。char為1個字節,所以a存放于0x0000中;int為4個字節,根據規則,b存儲的起始地址必須為其對齊模數4的整數倍,所以a后面自動填充空缺字節空間0x0001-0x0003,因此b存放于0x0004-0x0007中。long double是12個字節,由于32位系統每次最多分配4個字節,則首先分配0x0008-0x000B,由于不夠存儲空間,則繼續分配0x000C-0x000F,仍然不滿足存儲c,則繼續分配0x0010-0x0013,所以c存儲在0x0008-0x0013中,由于此時總存儲空間為4+4+12=20;則20滿足最大對齊模數4的整數倍;因此,sizeof(MyStruct)=20個字節。

注:以下的所有例子都是在win-32下實現

例2:

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

由上圖可知該結構體的最大對齊模數為sizeof(int)=4;假設B從地址空間0x0000開始存放。char為1個字節,所以a存放于0x0000中;int為4個字節,根據規則,b存儲的起始地址必須為其對齊模數4的整數倍,所以a后面自動填充空缺字節空間0x0001-0x0003,因此b存放于0x0004-0x0007中。c也是char類型,所以c存放在0x0008中;此時結構體B總的大小為4+4+1=9個字節;則9不能滿足最大對齊模數4的整數倍;因此在c的后面自動填充空間0x0009-0x000B,使其滿足最大對齊模數的倍數,最終結構體B的存儲空間為0x0000-0x000B;則sizeof(B)=12個字節。

例3:空結構體

struct C{   
}; 

sizeof(C) = 0或sizeof(C);C為空結構體,在C語言中占0字節,在C++中占1字節。

例4:結構體有靜態成員

struct D{   
   char a;   
   int b;   
   static double c; //靜態成員   
}; 

靜態成員變量存放在全局數據區內,在編譯的時候已經分配好內存空間,所以對結構體的總內存大小不做任何貢獻;因此,sizeof(D)=4+4=8個字節

例5:結構體中包含結構體

struct E{   
  int a;   
  double b;   
  float c;   
};   
struct F{   
  char e[2];   
  int f;   
  short h;   
  struct E i;   
}; 

在結構體E中最大對齊模數是sizeof(double)=8;且sizeof(E)=8+8+8=24個字節;在結構體F中,除了結構體成員E之外,其他的最大對齊模數是sizeof(int)=4;又因為結構體E中最大對齊模數是sizeof(double)=8;所以結構體F的最大對齊模數取E的最大對齊模數8;因此,sizeof(F)=4+4+8+24=40個字節。

例6:結構體包含共用體

union union1   
{   
  long a;   
  double b;   
  char name[9];   
  int c[2];   
};   
struct E{   
  int a;   
  double b;   
  float c;   
  union1 MyUnion;   
}; 

共用體中的最大對齊模式是sizeof(double)=8;則sizeof(union1)=16;結構體E的最大對齊模數也是8;則sizeof(E)=8+8+8+16=40個字節。

例7:結構體包含指針成員

typedef  struct A{   
    char a;   
    int b;   
    float c;   
    double d;   
    int *p;   
    char *pc;   
    short e;   
}A; 

結構體包含的指針成員的大小根據系統類型決定,由于這里是在win-32位系統下分析,則指針大小為4個字節;因此,結構體A的最大對齊模數為sizeof(double)=8;則sizeof(A)=4+4+8+8+4+4+8=40個字節。
存在#pragma pack宏的對齊

#pragma pack (n)//編譯器將按照n個字節對齊   
#pragma pack () //取消自定義字節對齊方式 

對齊規則
結構,聯合,或者類的數據成員,第一個放在偏移為0的地方,以后每個數據成員的對齊,按照#pragma pack指定的數值和自身對齊模數中較小的那個。

例8:按指定的對齊模數

 #pragma pack (2) /*指定按2字節對齊*/   
struct G{   
    char b;   
    int a;   
    double d;   
    short c;   
};   
 #pragma pack () /*取消指定對齊,恢復缺省對齊*/ 

在結構體G中成員變量的最大對齊模數是sizeof(double)=8;又因為指定對齊模數是2;所以取其較小者2為結構體G的最大對齊模數;則sizeof(G)=2+4+8+2=16;由于16是2的整數倍,則不需要填充。

總結

在分析結構體字節對齊時,首先確定有沒有利用#pragma pack()宏定義指定對齊模數;根據情況對應上面進行兩種情況分析,針對不同的系統會得到不同的結果。

補充:

在Visual C++下可以用__declspec(align(#))聲明數據按#字節對齊

GUN C下可以使用以下命令:

attribute((aligned (n))),讓所作用的結構成員對齊在n字節自然邊界上。如果結構中有成員的長度大于n,則按照最大成員的長度來對齊

attribute((packed)),取消結構在編譯過程中的優化對齊,按照實際占用字節數進行對齊。

C++11新加關鍵字alignas(n)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • @[c++|struct] 今天在編程中碰到一個坑,搞的調試了半天,最后發現程序中在寫數據和讀取數據時結構體定義不...
    drybeans閱讀 3,628評論 1 11
  • 轉載 結構體對齊詳解 結構體數據成員對齊的意義 許多實際的計算機系統對基本類型數據在內存中存放的位置有限制,它們會...
    erU閱讀 485評論 0 3
  • 首先感覺本文原作者的分享 w57w57w57的專欄-CSDN博客網址: http://blog.csdn.net/...
    HelloGeekBand閱讀 2,375評論 0 7
  • 引言 C語言結構體內存布局是一個老生常談的問題,網上也看了一些資料,有些說的比較模糊,有些是錯誤的。本人借鑒了前人...
    boborz閱讀 1,066評論 0 2
  • 前言:代碼規范最終的目的是降低代碼維護的成本。 代碼規范的好處(網上一搜一大把):http://kdboy.ite...
    道道明明白白閱讀 872評論 6 11