struct/class/union記憶體對齊原則有四個:
1).資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員,比如說是陣列,結構體等)的整數倍開始(比如int在32位機為4位元組, 則要從4的整數倍位址開始儲存),基本型別不包括struct/class/uinon。
2).結構體作為成員:如果乙個結構裡有某些結構體成員,則結構體成員要從其內部」最寬基本型別成員「的整數倍位址開始儲存.(struct a裡存有struct b,b裡有char,int ,double等元素,那b應該從8的整數倍開始儲存.)。
3).收尾工作:結構體的總大小,也就是sizeof的結果,.必須是其內部最大成員的」最寬基本型別成員」的整數倍.不足的要補齊.(基本型別不包括struct/class/uinon)。
4).sizeof(union),以結構裡面size最大元素為union的size,因為在某一時刻,union只有乙個成員真正儲存於該位址。
例項解釋:下面以class為代表
no.1
class data
;cout
<< sizeof(data) << endl;
no.2
class data
;cout
<< sizeof(data) << endl;
顯然程式no.1 輸出的結果為 8 no.2 輸出的結果為 16 .
no.1最大的資料成員是4bytes,1+4=5,補齊為4的倍數,也就是8。而no.2為8bytes,1+8=9,補齊為8的倍數,也就是16。
no.3
class data
;cout
<< sizeof(data) << endl;
no.4
class data
;cout
<< sizeof(data) << endl;
no.3執行結果為 12 no.4執行結果為 8
class中的資料成員放入記憶體的時候,記憶體拿出乙個記憶體塊來,資料成員們排隊乙個乙個往裡放,遇到太大的,不是把自己劈成兩半,能放多少放多少,而是等下乙個記憶體塊過來。這樣的話,就可以理解為什麼no.3,no.4兩端的**輸出結果不一樣了,因為左邊是1+(3)+4+1+(3)=12,而右邊是1+1+(2)+4=8。括號中為補齊的bytes。
no.5
class bigdata
;class data
;cout
<< sizeof(bigdata) << " "
<< sizeof(data) << endl;
no.6
class bigdata
;class data
;cout
<< sizeof(bigdata) << " "
<< sizeof(data) << endl;
no.5和no.6執行結果均為: 48
在預設條件下,記憶體對齊是以class中最大的那個基本型別為基準的,如果class中有自定義型別,則遞迴的取其中最大的基本型別來參與比較。在no.5和no.6中記憶體塊乙個接乙個的過來接走資料成員,一直到第5塊的時候,bigdata裡只剩1個char了,將它放入記憶體塊中,記憶體塊還剩7個bytes,接下來是個int(4bytes),能夠放下,所以也進入第5個記憶體塊,這時候記憶體塊還剩3bytes,而接下來是個double(8bytes),放不下,所以要等下乙個記憶體快到來。因此,no.5的data的size=33+4+(3)+8=48,同理no.6應該是33+(7)+8=48。
順便提一下union: 共用體表示幾個變數共用乙個記憶體位置,在不同的時間儲存不同的資料型別和不同長度的變數。在union中,所有的共用體成員共用乙個空間,並且同一時間只能儲存其中乙個成員變數的值。
no.7
class
aclass
b:public
aclass
c:public
b
sizeof(c)結果是多少呢,gcc和vs給出了不同的結果,分別是8、16
gcc中:c相當於把所有成員i、c1、c2、c3當作是在乙個class內部,(先繼承後對齊)
vs中:對於a,對齊後其大小是8;對於b,c2加上對齊後的a的大小是9,對齊後就是12;對於c,c3加上對齊後的b大小是13,再對齊就是16 (先對齊後繼承)
關於c++物件繼承後的記憶體布局,更詳細的分析可以《深度探索參考c++物件模型》第三章
記憶體對齊的主要作用是:
2、 效能原因:經過記憶體對齊後,cpu的記憶體訪問速度大大提公升。具體原因稍後解釋。
這是普通程式設計師心目中的記憶體印象,由乙個個的位元組組成,而cpu並不是這麼看待的。
cpu把記憶體當成是一塊一塊的,塊的大小可以是2,4,8,16位元組大小,因此cpu在讀取記憶體時是一塊一塊進行讀取的。塊大小成為memory access granularity(粒度) 本人把它翻譯為「記憶體讀取粒度」 。
假設cpu要讀取乙個int型4位元組大小的資料到暫存器中,分兩種情況討論:
1、資料從0位元組開始
2、資料從1位元組開始
再次假設記憶體讀取粒度為4。
當該資料是從0位元組開始時,很cpu只需讀取記憶體一次即可把這4位元組的資料完全讀取到暫存器中。
當該資料是從1位元組開始時,問題變的有些複雜,此時該int型資料不是位於記憶體讀取邊界上,這就是一類記憶體未對齊的資料。
此時cpu先訪問一次記憶體,讀取0—3位元組的資料進暫存器,並再次讀取4—5位元組的資料進暫存器,接著把0位元組和6,7,8位元組的資料剔除,最後合併1,2,3,4位元組的資料進暫存器。對乙個記憶體未對齊的資料進行了這麼多額外的操作,大大降低了cpu效能。
這還屬於樂觀情況了,上文提到記憶體對齊的作用之一為平台的移植原因,因為以上操作只有有部分cpu肯幹,其他一部分cpu遇到未對齊邊界就直接罷工了。
C 記憶體對齊原則及作用
內建型別資料成員 結構 struct class 的內建型別資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的起始位置要從自身大小的整數倍開始儲存 結構體作為成員 如果乙個結構裡有某些結構體成員,則結構體成員要從其內部 最寬基本型別成員 的整數倍位址開始儲存 如struct a裡...
C C 記憶體對齊原則及作用
1 資料成員對齊規則 結構 struct 或聯合 union 的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小或者成員的子成員大小 只要該成員有子成員,比如說是陣列,結構體等 的整數倍開始 比如int在 位機為 位元組,則要從 的整數倍位址開始儲存 ...
記憶體對齊 記憶體對齊規則解釋 記憶體對齊原理
一 記憶體對齊的原因 我們都知道計算機是以位元組 byte 為單位劃分的,理論上來說cpu是可以訪問任一編號的位元組資料的,我們又知道cpu的定址其實是通過位址匯流排來訪問記憶體的,cpu又分為32位和64位,在32位的cpu一次可以處理4個位元組 byte 的資料,那麼cpu實際定址的步長就是4個...