記憶體管理是c/c++程式設計非常重要的一部分內容,熟悉c/c++中一些常見資料結構和資料型別的記憶體分布情況,可以很大程度上降低了coding過程中記憶體洩漏和越界等比較嚴重的記憶體問題,下面主要討論一下結構體(類中同樣存在記憶體對齊,記憶體對齊會複雜一些,涉及到虛表等問題,後面介紹類的時候會提到)中的記憶體對齊問題。
一般來說,記憶體對齊過程對coding者來說是透明的,是由編譯器控制完成的
如對記憶體對齊有明確要求,可用#pragma pack(n)指定,以n和結構體中最長資料成員長度中較小者為有效值
如未明確指定時,以結構體中最長的資料成員長度作為記憶體對齊的有效值
以下如沒有特殊說明,均視為情況3(未明確指定)計算
資料成員對齊規則,結構體(struct)(或聯合(union))的資料成員,第乙個資料成員存放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小或者成員的子成員(只要該成員有子成員,比如陣列、結構體等)大小的整數倍開始(如:int 在 64bit 目標平台下占用 4byte,則要從4的整數倍位址開始儲存)
結構體作為成員,如果乙個結構體裡有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍位址開始儲存
結構體的總大小,即sizeof的結果,必須是其內部最大成員長度(即前面記憶體對齊指令中提到的有效值)的整數倍,不足的要補齊
陣列在記憶體中儲存時是分開儲存的,char型別的陣列每個元素是 1byte,記憶體對齊時按照單個元素進行對齊。
union(聯合體)型別中的資料共用記憶體,聯合的所有成員共用一段記憶體空間,儲存位址的起始位置都相同,一般來說最大成員的記憶體寬度作為union的記憶體大小,主要的原因是為了節省記憶體空間,預設的訪問許可權是公有的,但是它同樣要遵守記憶體對齊的原則,特別是第3條規則
c++中空結構體占用 1byte
c++中空類同樣是占用 1byte的記憶體空間(劍指offer 2.2.1節中中提到,當宣告該型別的例項的時候,必須在記憶體中占有一定的空間,否則無法使用這些例項,占用多少記憶體由編譯器決定)
結構體內部有數組成員時,因為當陣列第乙個元素對齊後,陣列其他元素就已經對齊。因此陣列內部各元素間不需要通過在陣列元素之間插入多餘位元組來實現對齊。
當結構體內部有 結構體物件成員時,查詢 結構體最大成員長度 時,除了比較普通成員長度,也需要比較 結構體物件成員的內部最大成員長度。取普通成員中的最大成員長度 和 結構體物件成員的內部最大成員長度 二者的最大值。
栗子1
struct test1
;
解釋:
int a; 占用 4byte(儲存位置0-3),規則1
double b; 占用 8byte(儲存位置是從該型別長度(也就是 8byte)或整數倍開始儲存8-15),規則1
char c; 占用 1byte(儲存位置16),規則1
這時一共用了17 byte,但是sizeof所得的大小為24,這就用到了第3條規則,最後sizeof的大小還必須是內部最大成員長度的整數倍,不足的要補齊,這個結構體中最大成員是double b; 8 byte,最後sizeof的大小為24,規則3
栗子2
struct test2
;
解釋:
int a; 占用 4byte(儲存位置0-3),規則1
double b; 占用 8byte(儲存位置是從該型別長度(也就是 8byte)或整數倍開始儲存8-15),規則1
陣列在記憶體中儲存時是分開儲存的,char型別的陣列每個元素是 1byte,按單個元素進行記憶體對齊,故sizeof大小還是24,注意1 & 規則3
栗子3
struct test
;struct test3
;
解釋:
int a; 占用 4byte(儲存位置0-3),規則1
test中最大的元素是double b; 占用 8byte,test中的成員是按照 8byte 的整數倍的位址開始儲存的,test中int a; 占用 4byte(儲存位置8-11),double b; 占用 8byte(儲存位置16-23),char c; 占用 1byte(儲存位置24),規則2
double b; 占用 8byte(儲存位置32-39),規則1
char c; 占用1 byte(儲存位置40),不是最大元素大小8的整數倍,按照規則3補齊,sizeof為48,規則1 & 規則2 & 規則3
栗子4
struct test
;struct test3
;
解釋:
test3中的最大資料成員大小比成員結構體test內部最大成員大小要小,這時規則3是按照成員結構體內部的最大成員的整數倍進行補齊的,sizeof的結果是40
栗子5
union test
;
解釋:
sizeof的大小是20,即a[20]的大小,同樣20是b和c的倍數,規則3
栗子6
union test
;
解釋:
sizeof的大小是24,即滿足容下a[20],同樣20是b、c和d的倍數,規則3
平台原因(移植原因),不是所有的硬體平台都能任意訪問位址上的任意資料的,某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常
效能原因,經過記憶體對齊後,cpu的訪問效率會得到很大的提高(cpu把記憶體當成是一塊一塊的,塊的大小可以是2,4,8,16byte 大小,因此cpu在讀取記憶體時是一塊一塊進行讀取的,當讀取塊的大小是 4byte 時,乙個資料所佔的位元組偏移(offset)為3|4|5|6,那麼cpu訪問資料時便需要訪問兩次,才能得到完整的資料,經過記憶體對齊後,便可以通過一次訪問cpu獲取完整的資料 [引用自]
例子:
#define u32 unsigned int
struct test
;struct test2
;struct test3
;struct test4
;void
struct_test()
輸出:
// x86目標平台執行結果
參考:
結構體對齊(記憶體對齊
有的時候,在腦海中停頓了很久的 顯而易見 的東西,其實根本上就是錯誤的。就拿下面的問題來看 structt 使用sizeof t 將得到什麼樣的答案呢?要是以前,想都不用想,在32位機中,int是4個位元組,char是1個位元組,所以t一共是5個位元組。實踐出真知,在vc6中測試了下,答案確實8個位...
記憶體對齊 結構體對齊
現在已知32位機器上各種資料型別的長度如下 char 1 有符號無符號同 short 2 有符號無符號同 int 4 有符號無符號同 long 4 有符號無符號同 float 4 double 8 重要規則 1,複雜型別中各個成員按照它們被宣告的順序在記憶體中順序儲存,第乙個成員的位址和整個型別的位...
C C 結構體對齊原則
先介紹四個概念 1 資料型別自身的對齊值 基本資料型別的自身對齊值,等於sizeof 基本資料型別 2 指定對齊值 pragma pack value 時的指定對齊值value。3 結構體或者類的自身對齊值 其成員中自身對齊值最大的那個值。4 資料成員 結構體和類的有效對齊值 自身對齊值和指定對齊值...