一、字節對齊的原因
在訪問內存時,如果地址是按4字節對齊,則訪問效率會高很多。這種現象的原因在於訪問內存的硬件電路。一般情況下,地址總線總是按照對齊後的地址來訪問。例如,你想得到0x00000001開始的四字節內容,系統首先需要以0x00000000讀四字節,從中取得3字節,然後再用0x00000004作爲開始地址,獲得下一個4字節,再從中得到第一個字節,再次組合出需要得到的內容。但是,如果地址從一開始就是對齊到0x00000000,則系統只要一次讀寫即可。
考慮到性能方面,編譯器會對結構進行對齊處理。
二、C++字節對齊的規則
在沒有使用#pragma pack的情況下,字節對齊大致有以下三條規則:
1.數據成員對齊規則:struct, union的數據成員,第一個數據成員放在offset爲0的地方,之後的數據成員的存儲起始位置都是放在該數據成員大小的整數倍位置。如在32bit的機器上,int的大小爲4,因此int存儲的位置都是4的整數倍的位置開始存儲。
2.結構體作爲數據成員的對齊規則:在一個struct中包含另一個struct,內部struct應該以它的最大數據成員大小的整數倍開始存儲。如 struct A 中包含 struct B, struct B 中包含數據成員 char, int, double,則 struct B 應該以sizeof(double)=8的整數倍爲起始地址。
3.收尾工作的對齊規則:整個struct的大小,應該爲最大數據成員大小的整數倍。
例如:定義如下類:
class MyClass
{
public:
MyClass();
~MyClass();
public:
int a;
char b;
int c;
private:
};
執行如下代碼:
MyClass myclass;
printf("0x%08x\n", &myclass.a);
printf("0x%08x\n", &myclass.b);
printf("0x%08x\n", &myclass.c);
輸出結果如下:
可以看到myclass類裏邊變量a和c是int類型,b是char類型,a在內存中開始的地址是4的倍數,雖然b只佔用一個字節,但是爲了滿足c內存地址的開始是4的倍數,b和c之間有三個字節的內存單元沒有被佔用。
在VC中,使用pack預處理指令來調整字節對齊的規則。
使用#pragma pack(n),指定c編譯器按照n個字節對齊;
定義如下類:
class MyClass
{
public:
MyClass();
~MyClass();
public:
<span style="font-family:SimSun;">double</span> d;
float a;
char e;
int b;
char c;
private:
};
執行如下代碼:
int _tmain(int argc, _TCHAR* argv[])
{
cout << sizeof(MyClass) << endl;
return 0;
}
在未使用#pragma pack()時,輸出結果爲:
使用#pragma pack()後,輸出結果爲: