程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深刻分析C++中的struct構造體字節對齊

深刻分析C++中的struct構造體字節對齊

編輯:關於C++

深刻分析C++中的struct構造體字節對齊。本站提示廣大學習愛好者:(深刻分析C++中的struct構造體字節對齊)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻分析C++中的struct構造體字節對齊正文


甚麼是字節對齊,為何要對齊?

古代盤算機中內存空間都是依照byte劃分的,從實際上講仿佛對任何類型的變量的拜訪可以從任何地址開端,但現實情形是在拜訪特定類型變量的時刻常常在特 定的內存地址拜訪,這就須要各類類型數據依照必定的規矩在空間上分列,而不是次序的一個接一個的排放,這就是對齊。

對齊的感化和緣由:各個硬件平台對存儲空間的處置上有很年夜的分歧。一些平台對某些特定類型的數據只能從某些特定地址開端存取。好比有些架構的CPU在拜訪一個沒有停止對齊的變量的時刻會產生毛病,那末在這類架構下編程必需包管字節對齊.其他平台能夠沒有這類情形,然則最多見的是假如不依照合適其平台請求對數據寄存停止對齊,會在存取效力上帶來喪失。好比有些平台每次讀都是從偶地址開端,假如一個int型(假定為32位體系)假如寄存在偶地址開端的處所,那末一個讀周期便可以讀出這32bit,而假如寄存在奇地址開端的處所,就須要2個讀周期,並對兩次讀出的成果的高下字節停止拼集能力獲得該32bit數據。明顯在讀取效力高低降許多。

構造的存儲分派
編譯器依照構造體成員列表的次序為每一個成員分派內存,當存儲成員時須要知足准確地界限對齊請求時,成員之間能夠湧現用於填充地額定內存空間。32位體系每次分派字節數最多為4個字節,64位體系分派字節數最多為8個字節。
以下圖表是在分歧體系中根本類型數據內存年夜小和默許對齊模數:
注:另外指針所占內存的長度由體系決議,在32位體系下為32位(即4個字節),64位體系下則為64位(即8個字節).

沒有#pragma pack宏的對齊
對齊規矩:

構造體的肇端存儲地位必需是可以或許被該構造體中最年夜的數據類型所整除。
每一個數據成員存儲的肇端地位是本身年夜小的整數倍(好比int在32位機為4字節,則int型成員要從4的整數倍地址開端存儲)。
構造體總年夜小(也就是sizeof的成果),必需是該構造體成員中最年夜的對齊模數的整數倍。若不知足,會依據須要主動填充空白的字節。
構造體包括另外一個構造體成員,則被包括的構造體成員要從其原始構造體外部最年夜對齊模數的整數倍地址開端存儲。(好比struct a裡存有struct b,b裡有char,int,double等元素,那b應當從8的整數倍開端存儲。)
構造體包括數構成員,好比char a[3],它的對齊方法和分離寫3個char是一樣的,也就是說它照樣按一個字節對齊。假如寫:typedef char Array[3],Array這類類型的對齊方法照樣按一個字節對齊,而不是按它的長度3對齊。
構造體包括共用體成員,則該共用體成員要從其原始共用體外部最年夜對齊模數的整數倍地址開端存儲。
如今給出一個構造體,我們針對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)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved