亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入剖析C++中的struct結(jié)構(gòu)體字節(jié)對(duì)齊

 更新時(shí)間:2016年05月18日 17:13:45   作者:drybeans  
要求數(shù)據(jù)內(nèi)存的起始地址的值是某個(gè)數(shù)k的倍數(shù),這就是所謂的內(nèi)存對(duì)齊,本文就來(lái)深入剖析C++中的struct結(jié)構(gòu)體字節(jié)對(duì)齊,需要的朋友可以參考下

什么是字節(jié)對(duì)齊,為什么要對(duì)齊?

現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對(duì)任何類(lèi)型的變量的訪問(wèn)可以從任何地址開(kāi)始,但實(shí)際情況是在訪問(wèn)特定類(lèi)型變量的時(shí)候經(jīng)常在特 定的內(nèi)存地址訪問(wèn),這就需要各種類(lèi)型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個(gè)接一個(gè)的排放,這就是對(duì)齊。

對(duì)齊的作用和原因:各個(gè)硬件平臺(tái)對(duì)存儲(chǔ)空間的處理上有很大的不同。一些平臺(tái)對(duì)某些特定類(lèi)型的數(shù)據(jù)只能從某些特定地址開(kāi)始存取。比如有些架構(gòu)的CPU在訪問(wèn)一個(gè)沒(méi)有進(jìn)行對(duì)齊的變量的時(shí)候會(huì)發(fā)生錯(cuò)誤,那么在這種架構(gòu)下編程必須保證字節(jié)對(duì)齊.其他平臺(tái)可能沒(méi)有這種情況,但是最常見(jiàn)的是如果不按照適合其平臺(tái)要求對(duì)數(shù)據(jù)存放進(jìn)行對(duì)齊,會(huì)在存取效率上帶來(lái)?yè)p失。比如有些平臺(tái)每次讀都是從偶地址開(kāi)始,如果一個(gè)int型(假設(shè)為32位系統(tǒng))如果存放在偶地址開(kāi)始的地方,那么一個(gè)讀周期就可以讀出這32bit,而如果存放在奇地址開(kāi)始的地方,就需要2個(gè)讀周期,并對(duì)兩次讀出的結(jié)果的高低字節(jié)進(jìn)行拼湊才能得到該32bit數(shù)據(jù)。顯然在讀取效率上下降很多。

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

2016518170752299.png (675×267)

沒(méi)有#pragma pack宏的對(duì)齊
對(duì)齊規(guī)則:

結(jié)構(gòu)體的起始存儲(chǔ)位置必須是能夠被該結(jié)構(gòu)體中最大的數(shù)據(jù)類(lèi)型所整除。
每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置是自身大小的整數(shù)倍(比如int在32位機(jī)為4字節(jié),則int型成員要從4的整數(shù)倍地址開(kāi)始存儲(chǔ))。
結(jié)構(gòu)體總大小(也就是sizeof的結(jié)果),必須是該結(jié)構(gòu)體成員中最大的對(duì)齊模數(shù)的整數(shù)倍。若不滿足,會(huì)根據(jù)需要自動(dòng)填充空缺的字節(jié)。
結(jié)構(gòu)體包含另一個(gè)結(jié)構(gòu)體成員,則被包含的結(jié)構(gòu)體成員要從其原始結(jié)構(gòu)體內(nèi)部最大對(duì)齊模數(shù)的整數(shù)倍地址開(kāi)始存儲(chǔ)。(比如struct a里存有struct b,b里有char,int,double等元素,那b應(yīng)該從8的整數(shù)倍開(kāi)始存儲(chǔ)。)
結(jié)構(gòu)體包含數(shù)組成員,比如char a[3],它的對(duì)齊方式和分別寫(xiě)3個(gè)char是一樣的,也就是說(shuō)它還是按一個(gè)字節(jié)對(duì)齊。如果寫(xiě):typedef char Array[3],Array這種類(lèi)型的對(duì)齊方式還是按一個(gè)字節(jié)對(duì)齊,而不是按它的長(zhǎng)度3對(duì)齊。
結(jié)構(gòu)體包含共用體成員,則該共用體成員要從其原始共用體內(nèi)部最大對(duì)齊模數(shù)的整數(shù)倍地址開(kāi)始存儲(chǔ)。
現(xiàn)在給出一個(gè)結(jié)構(gòu)體,我們針對(duì)win-32和Linux-32進(jìn)行分析,

例1:

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

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

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

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

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

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

struct C{ 
  };
sizeof(C) = 0或sizeof(C);

C為空結(jié)構(gòu)體,在C語(yǔ)言中占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),在編譯的時(shí)候已經(jīng)分配好內(nèi)存空間,所以對(duì)結(jié)構(gòu)體的總內(nèi)存大小不做任何貢獻(xiàn);因此,sizeof(D)=4+4=8個(gè)字節(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中最大對(duì)齊模數(shù)是sizeof(double)=8;且sizeof(E)=8+8+8=24個(gè)字節(jié);在結(jié)構(gòu)體F中,除了結(jié)構(gòu)體成員E之外,其他的最大對(duì)齊模數(shù)是sizeof(int)=4;又因?yàn)榻Y(jié)構(gòu)體E中最大對(duì)齊模數(shù)是sizeof(double)=8;所以結(jié)構(gòu)體F的最大對(duì)齊模數(shù)取E的最大對(duì)齊模數(shù)8;因此,sizeof(F)=4+4+8+24=40個(gè)字節(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; 
};

共用體中的最大對(duì)齊模式是sizeof(double)=8;則sizeof(union1)=16;結(jié)構(gòu)體E的最大對(duì)齊模數(shù)也是8;則sizeof(E)=8+8+8+16=40個(gè)字節(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)類(lèi)型決定,由于這里是在win-32位系統(tǒng)下分析,則指針大小為4個(gè)字節(jié);因此,結(jié)構(gòu)體A的最大對(duì)齊模數(shù)為sizeof(double)=8;則sizeof(A)=4+4+8+8+4+4+8=40個(gè)字節(jié)。

存在#pragma pack宏的對(duì)齊

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

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

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

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

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

補(bǔ)充:
在Visual C++下可以用__declspec(align(#))聲明數(shù)據(jù)按#字節(jié)對(duì)齊
GUN C下可以使用以下命令:
__attribute__((aligned (n))),讓所作用的結(jié)構(gòu)成員對(duì)齊在n字節(jié)自然邊界上。如果結(jié)構(gòu)中有成員的長(zhǎng)度大于n,則按照最大成員的長(zhǎng)度來(lái)對(duì)齊
__attribute__((__packed__)),取消結(jié)構(gòu)在編譯過(guò)程中的優(yōu)化對(duì)齊,按照實(shí)際占用字節(jié)數(shù)進(jìn)行對(duì)齊。
C++11新加關(guān)鍵字alignas(n)

相關(guān)文章

  • C++異常處理入門(mén)(try和catch)

    C++異常處理入門(mén)(try和catch)

    C++ 提供了異常機(jī)制,讓我們能夠捕獲運(yùn)行時(shí)錯(cuò)誤,本文就詳細(xì)的介紹了C++異常處理入門(mén),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • c語(yǔ)言之char*和unsigned?char*的區(qū)別及說(shuō)明

    c語(yǔ)言之char*和unsigned?char*的區(qū)別及說(shuō)明

    這篇文章主要介紹了c語(yǔ)言之char*和unsigned?char*的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 在c和c++中實(shí)現(xiàn)函數(shù)回調(diào)

    在c和c++中實(shí)現(xiàn)函數(shù)回調(diào)

    如何在c和c++中實(shí)現(xiàn)函數(shù)回調(diào)呢?現(xiàn)在小編就和大家分享一下在c/c++中實(shí)現(xiàn)函數(shù)回調(diào)的示例代碼,需要的朋友可以參考下
    2013-07-07
  • C語(yǔ)言基于EasyX庫(kù)實(shí)現(xiàn)有顏色彈跳小球

    C語(yǔ)言基于EasyX庫(kù)實(shí)現(xiàn)有顏色彈跳小球

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言基于EasyX庫(kù)實(shí)現(xiàn)有顏色彈跳小球,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C語(yǔ)言sizeof和strlen的指針和數(shù)組面試題詳解

    C語(yǔ)言sizeof和strlen的指針和數(shù)組面試題詳解

    strlen是函數(shù),字符串長(zhǎng)度,不包括停止符。而sizeof則是內(nèi)存塊的大小,包括停止符。數(shù)組是一種數(shù)據(jù)類(lèi)型,數(shù)據(jù)類(lèi)型的本質(zhì)就是固定大小,內(nèi)存塊的別名??梢杂胹izeof()一般都是數(shù)據(jù)類(lèi)型
    2022-04-04
  • C++筆記之std::future的用法小結(jié)

    C++筆記之std::future的用法小結(jié)

    std::future通常由某個(gè)Provider創(chuàng)建,與std::async一起使用,本文主要介紹了C++筆記之std::future的用法小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • C++ typeid 和虛函數(shù)詳解

    C++ typeid 和虛函數(shù)詳解

    這篇文章主要介紹了c++ typeid 和虛函數(shù)的使用,幫助大家更好的理解和使用c++,感興趣的朋友可以了解下,希望能夠給你帶來(lái)幫助
    2021-09-09
  • 使用代碼驗(yàn)證linux子進(jìn)程與父進(jìn)程的關(guān)系

    使用代碼驗(yàn)證linux子進(jìn)程與父進(jìn)程的關(guān)系

    Linux下父進(jìn)程可以使用fork 函數(shù)創(chuàng)建子進(jìn)程,但是當(dāng)父進(jìn)程先退出后,子進(jìn)程會(huì)不會(huì)也退出呢?通過(guò)下面這個(gè)小實(shí)驗(yàn),我們能夠很好的看出來(lái)
    2014-02-02
  • C語(yǔ)言與java語(yǔ)言中關(guān)于二維數(shù)組的區(qū)別

    C語(yǔ)言與java語(yǔ)言中關(guān)于二維數(shù)組的區(qū)別

    這篇文章主要介紹了C語(yǔ)言與java語(yǔ)言中關(guān)于二維數(shù)組的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • C++實(shí)現(xiàn)教務(wù)管理系統(tǒng)

    C++實(shí)現(xiàn)教務(wù)管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)教務(wù)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評(píng)論