大家都知道,C++空類的內存大小為1字節,為了保證其對象擁有彼此獨立的內存地址。非空類的大小與類中非靜態成員變量和虛函數表的多少有關。
而值得注意的是,類中非靜態成員變量的大小與編譯器內存對齊的設置有關。
成員變量在類中的內存存儲並不一定是連續的。它是按照編譯器的設置,按照內存塊來存儲的,這個內存塊大小的取值,就是內存對齊。
一、引入問題。
#include<iostream> using namespace std; class test { private : char c='1';//1byte int i;//4byte short s=2;//2byte }; int main(){ cout << sizeof(test) << endl; return 0; }
輸出:12
class test2 { private: int i;//4byte char c = '1';//1byte short s = 2;//2byte }; int main(){ cout << sizeof(test2) << endl; return 0; }
輸出:8
我們可以看到。類test和test2的成員變量完全一樣,只是定義順序不一樣,卻造成了2個類占用內存大小不一樣。而這就是編譯器內存對齊的緣故。
二、規則
1、第一個數據成員放在offset為0的地方,以後每個數據成員的對齊按照#pragma pack指定的數值和這個數據成員自身長度中,比較小的那個進行。
2、在數據成員完成各自對齊之後,類(結構或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大數據成員長度中,比較小的那個進行。
很明顯#pragma pack(n)作為一個預編譯指令用來設置多少個字節對齊的。值得注意的是,n的缺省數值是按照編譯器自身設置,一般為8,合法的數值分別是1、2、4、8、16。
即編譯器只會按照1、2、4、8、16的方式分割內存。若n為其他值,是無效的。
三、問題分析
(1)對於類test的內存空間是這樣的:
內存分配過程:
1、char和編譯器默認的內存缺省分割大小比較,char比較小,分配一個字節給它。
2、int和編譯器默認的內存缺省分割大小比較,int比較小,占4字節。只能空3個字節,重新分配4個字節。
3、short和編譯器默認的內存缺省分割大小比較,short比較小,占2個字節,分配2個字節給它。
4、對齊結束類本身也要對齊,所以最後空余的2個字節也被test占用。
(2)對於類test2的內存空間是這樣的:
1、int和編譯器默認的內存缺省分割大小比較,int比較小,占4字節。分配4個字節給int。
2、char和編譯器默認的內存缺省分割大小比較,char比較小,分配一個字節給它。
3、short和編譯器默認的內存缺省分割大小比較,short比較小,此時前面的char分配完畢還余下3個字節,足夠short的2個字節存儲,所以short緊挨著。分配2個字節給short。
4、對齊結束類本身也要對齊,所以最後空余的1個字節也被test占用。
(3)使用#pragma pack(n)
#include<iostream> using namespace std; #pragma pack(1)//設定為 1 字節對齊 class test { private : char c='1';//1byte int i;//4byte short s=2;//2byte }; class test2 { private: int i;//4byte char c = '1';//1byte short s = 2;//2byte }; int main(){ cout << sizeof(test) << endl; cout << sizeof(test2) << endl; return 0; }
輸出:
可以看到,當我們把編譯器的內存分割大小設置為1後,類中所有的成員變量都緊密的連續分布。
至此,C++內存對齊總結已經差不多了。想要更多了解C++對象內存分配推薦陳浩的2篇文章:
http://blog.csdn.net/haoel/article/details/3081328
和http://blog.csdn.net/haoel/article/details/1948051
陳浩大神寫的太透徹了。
參考:http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html
http://www.jb51.net/article/45406.htm