struct/union/class內存對齊原則有四個:
1).數據成員對齊規則:結構(struct)(或聯合(union))的數據成員,第一個數據成員放在offset為0的地方,以后每個數據成員存儲的起始位置要從該成員大小或者成員的子成員大小(只要該成員有子成員,比如說是數組,結構體等)的整數倍開始(比如int在32位機為4字節, 則要從4的整數倍地址開始存儲),基本類型不包括struct/uinon/class。
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
{
char c;
int a;
};
cout << sizeof(Data) << endl;
No.2
class Data
{
char c;
double a;
};
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
{
char c;
int a;
char d;
};
cout << sizeof(Data) << endl;
No.4
class Data
{
char c;
char d;
int a;
};
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
{
char array[33];
};
class Data
{
BigData bd;
int integer;
double d;
};
cout << sizeof(BigData) << " " << sizeof(Data) << endl;
No.6
class BigData
{
char array[33];
};
class Data
{
BigData bd;
double d;
};
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中,所有的共用體成員共用一個空間,並且同一時間只能儲存其中一個成員變量的值。
以上內容部分轉載自http://www.cnblogs.com/biyeymyhjob/archive/2012/09/07/2674992.html
拓展:
1、整型
int 4字節
long int 4字節
short int 2字節
unsigned long int 4字節
unsigned short int 2字節
2、字符型
char 1字節
unsigned char 1字節
3、浮點型
float 4字節
double 8字節
long double 8字節
unsigned long double 8字節
unsigned double 4字節
4、字符串型
string 32字節
5、指針類型
所有類型的指針都是 4字節 (但是在64位下為8字節)
二、字節對齊原則
在系統默認的對齊方式下:每個成員相對於這個結構體變量地址的偏移量正好是該成員類型所占字節的整數倍,且最終占用字節數為成員類型中最大占用字節數的整數倍。
三、C++類中的數據成員也遵循以上對齊原則,即:
1.在不考慮(或者說在沒有)虛函數和虛繼承的情況下,sizeof(自定義類)也按照類似上面的方式來計算。
2.但如果一個類擁有虛函數或者虛繼承,則在數據成員的基礎上相當於多一個指針類型的數據成員(位置在所有數據成員的前面),最后計算時加上即可。
3.靜態(static)成員不在計算范圍。
[簡言之,類的大小與成員變量(非static數據成員變量)和虛函數指針有關(注意:虛函數中有一個指向虛函數列表的指針,無論有多少個虛函數都是占用一個字節的大小)]
4.如果一個類或者結構體不含有任何數據成員,且無虛函數以及虛繼承,則sizeof()結構為1。
四、為什么要進行字節對齊?
《Windows核心編程》里這樣說:當CPU訪問正確對齊的數據時,它的運行效率最高,當數據大小的數據模數的內存地址是0時,數據是對齊的。例如:WORD值應該是總是從被2除盡的地址開始,而DWORD值應該總是從被4除盡的地址開始,數據對齊不是內存結構的一部分,而是CPU結構的一部分。當CPU試圖讀取的數值沒有正確的對齊時,CPU可以執行兩種操作之一:產生一個異常條件;執行多次對齊的內存訪問,以便讀取完整的未對齊數據,若多次執行內存訪問,應用程序的運行速度就會慢。
可參考webary的blog:http://www.cnblogs.com/webary/p/4721017.html
