關於c++對象的內存模型 - 【內存對齊】方面,網上有大把的資料對此進行介紹,本篇文章僅對這些內容做一個梳理。
對齊規則,不同編譯器存在差異,本文在“vc6/32bit”windows平台進行編譯測試。(缺省為8字節對齊:對應編譯選項/Zp8)
0.示例代碼:
1 #pragma pack(1) // 以1字節方式對齊 2 class A1 3 { 4 char a; 5 short b; 6 }; 7 #pragma pack() // 使用缺省對齊方式 8 9 class A2 10 { 11 char a; 12 short b; 13 }; 14 15 /* 測試 */ 16 int a1 = sizeof(A1); // 3 17 int a2 = sizeof(A2); // 4
A1內存模型(大小:3字節)
A2內存模型(大小:4字節)
1. 偽命令用法說明:
#pragma pack(n) // 使用自定義n字節對齊 n可以為1,2,4,8,16
#pragma pack() // 使用缺省字節對齊(缺省為8字節對齊)
#pragma Pack(push) // 存放當前字節對齊到棧頂
#pragma Pack(push, n) // 將n字節對齊方式壓入棧頂,並啟用自定義n字節對齊方式
/*** 等價於 ***/
=> #pragma Pack(push)
=> #pragma Pack(n)
#pragma Pack(pop) // 彈出棧頂,然后啟用新棧頂字節對齊方式【彈出后,棧為空,則恢復為缺省字節對齊】
2. 詳細解釋:
3. 內存對齊規則
(1)對於class(struct/union)的各個成員,第一個成員位於偏移為0的位置,以后每個數據成員的偏移量必須是min{#pragma pack()指定的數,該數據成員的自身長度} 的倍數。
(2)在數據成員完成各自對齊之后,class(struct/union)本身也要按照min{#pragma pack()指定的數,class(struct/union)中最大基本數據成員長度}進行對齊。
4. 為什么要內存對齊
(1)硬件限制:不是所有的硬件平台都能訪問任意地址上的數據;某些硬件平台只能在某些地址處取特定類型的數據,否則拋出硬件異常。
(2)提高性能:內存8字節對齊(注:cpu訪問byte、WORD、DWORD、__int64類型的數據時,只用一次內存訪問)后,CPU的內存訪問速度大大提升。
5. 那些情況要考慮內存對齊
(1)在不同平台之間(比如在Windows 與Linux之間),不同模塊之間(dll與exe之間)傳遞二進制流(比如結構體),必須要定義相同的對齊方式。
(2)序列化與反序列化的操作時,也必須要定義相同的對齊方式。
6. 補充
對於gcc編譯器:
__attribute((aligned (n))) 讓所作用的結構成員對齊在n字節自然邊界上。如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。
__attribute__ ((packed)) 取消結構在編譯過程中的優化對齊,按照實際占用字節數進行對齊。
// sizeof(struct test)=8 struct test { char x1; short x2; float x3; char x4; }__attribute__ ((packed));
visual studio編譯器的為:
__declspec(align(n)) 讓所作用的結構成員對齊在n字節自然邊界上。如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。
__declspec(align(32)) struct Str1 { int a, b, c, d, e; };
7. 外部參考 http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html