(轉(zhuǎn))操作系統(tǒng)學(xué)習(xí)(五)——64位系統(tǒng)與32位系統(tǒng)在數(shù)據(jù)結(jié)構(gòu)占用上的區(qū)別

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

前言

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

結(jié)構(gòu)的存儲分配

編譯器按照結(jié)構(gòu)體成員列表的順序?yàn)槊總€成員分配內(nèi)存,當(dāng)存儲成員時需要滿足正確地邊界對齊要求時,成員之間可能出現(xiàn)用于填充地額外內(nèi)存空間。32位系統(tǒng)每次分配字節(jié)數(shù)最多為4個字節(jié),64位系統(tǒng)分配字節(jié)數(shù)最多為8個字節(jié)。
以下圖表是在不同系統(tǒng)中基本類型數(shù)據(jù)內(nèi)存大小和默認(rèn)對齊模數(shù):



注:此外指針?biāo)純?nèi)存的長度由系統(tǒng)決定,在32位系統(tǒng)下為32位(即4個字節(jié)),64位系統(tǒng)下則為64位(即8個字節(jié)).

沒有#pragma pack宏的對齊

對齊規(guī)則 :

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

現(xiàn)在給出一個結(jié)構(gòu)體,我們針對win-32和Linux-32進(jìn)行分析,例1:

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

解答

win-32位系統(tǒng)下

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

Linux-32位系統(tǒng)下:

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

注:以下的所有例子都是在win-32下實(shí)現(xiàn)

例2:

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

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

例3:空結(jié)構(gòu)體

struct C{   
}; 

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

例4:結(jié)構(gòu)體有靜態(tài)成員

struct D{   
   char a;   
   int b;   
   static double c; //靜態(tài)成員   
}; 

靜態(tài)成員變量存放在全局?jǐn)?shù)據(jù)區(qū)內(nèi),在編譯的時候已經(jīng)分配好內(nèi)存空間,所以對結(jié)構(gòu)體的總內(nèi)存大小不做任何貢獻(xiàn);因此,sizeof(D)=4+4=8個字節(jié)

例5:結(jié)構(gòu)體中包含結(jié)構(gòu)體

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

在結(jié)構(gòu)體E中最大對齊模數(shù)是sizeof(double)=8;且sizeof(E)=8+8+8=24個字節(jié);在結(jié)構(gòu)體F中,除了結(jié)構(gòu)體成員E之外,其他的最大對齊模數(shù)是sizeof(int)=4;又因?yàn)榻Y(jié)構(gòu)體E中最大對齊模數(shù)是sizeof(double)=8;所以結(jié)構(gòu)體F的最大對齊模數(shù)取E的最大對齊模數(shù)8;因此,sizeof(F)=4+4+8+24=40個字節(jié)。

例6:結(jié)構(gòu)體包含共用體

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;結(jié)構(gòu)體E的最大對齊模數(shù)也是8;則sizeof(E)=8+8+8+16=40個字節(jié)。

例7:結(jié)構(gòu)體包含指針成員

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

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

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

對齊規(guī)則
結(jié)構(gòu),聯(lián)合,或者類的數(shù)據(jù)成員,第一個放在偏移為0的地方,以后每個數(shù)據(jù)成員的對齊,按照#pragma pack指定的數(shù)值和自身對齊模數(shù)中較小的那個。

例8:按指定的對齊模數(shù)

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

在結(jié)構(gòu)體G中成員變量的最大對齊模數(shù)是sizeof(double)=8;又因?yàn)橹付▽R模數(shù)是2;所以取其較小者2為結(jié)構(gòu)體G的最大對齊模數(shù);則sizeof(G)=2+4+8+2=16;由于16是2的整數(shù)倍,則不需要填充。

總結(jié)

在分析結(jié)構(gòu)體字節(jié)對齊時,首先確定有沒有利用#pragma pack()宏定義指定對齊模數(shù);根據(jù)情況對應(yīng)上面進(jìn)行兩種情況分析,針對不同的系統(tǒng)會得到不同的結(jié)果。

補(bǔ)充:

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

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

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

attribute((packed)),取消結(jié)構(gòu)在編譯過程中的優(yōu)化對齊,按照實(shí)際占用字節(jié)數(shù)進(jìn)行對齊。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容