現代 CPU 從記憶體讀取資料時,若資料位址符合其類型大小的倍數(如 int 位址為 4 的倍數),可單一總線週期完成;否則需兩次讀取並拼湊,嚴重影響效能。某些架構(如 SPARC、ARM 舊版)甚至直接觸發硬體例外。編譯器因此自動在結構體成員間插入填充位元組,確保每個成員位址滿足對齊需求。
| 類型 | 大小 | 對齊要求 (位址模值) |
|---|---|---|
| char | 1 | 1 |
| short | 2 | 2 |
| int / long / float | 4 | 4 |
| double | 8 | 8 |
| 指標 | 4 | 4 |
結構體整體大小 必須為「最大成員對齊值」的倍數,尾部亦會填充。
double, char, intstruct A { double d; char c; int i; };
// 佈局:
// offset 0-7 : d (8 bytes, aligned 8)
// offset 8 : c (1 byte)
// offset 9-11 : padding (3 bytes) -> align int to 4
// offset 12-15: i (4 bytes)
// 總大小 = 16 (8 的倍數)
char, double, int (順序調換)struct B { char c; double d; int i; };
// offset 0 : c (1)
// offset 1-7 : padding (7) -> align double to 8
// offset 8-15 : d (8)
// offset 16-19: i (4)
// 尾部 padding 4 bytes -> 總大小 24 (8 的倍數)
// 填充總計 11 bytes!
結論:成員排序影響記憶體佔用,建議按大小遞減排列。
n >= sizeof(member) → 依預設對齊。n < sizeof(member) → 以 n 為對齊單位。n 大於所有成員 → 最大成員對齊值倍數;否則為 n 的倍數。#pragma pack(4)#pragma pack(push)
#pragma pack(4)
struct Test { char m1; double m4; int m3; };
#pragma pack(pop)
// 佈局 (4-byte alignment):
// m1: offset 0 (1 byte)
// padding 3 -> offset 4
// m4: offset 4 (8 bytes) // 4 < 8, 但 pack(4) 允許 4-byte align for double?
// 實測 VC: double 仍要求 8-byte align?
// 修正:VC 中 #pragma pack(n) 對基本類型仍受限於其自然對齊,除非 n >= 自然對齊。
// 實際 VC6 行為:pack(4) 時 double 仍靠 8,故大小 24。
// pack(1) 時才會強制緊湊。
更正:MSVC 中 #pragma pack(n) 實際行為為 取 min(n, 自然對齊)。若 n=4,double 自然對齊 8,取 min(4,8)=4 → 允許 4-byte 對齊。但實測 VC6.0 pack(4) 下 double 仍置於 offset 8(8-byte align),故建議以 pack(1) 強制緊湊,或依賴自然對齊。
#pragma pack(8)
struct S1 { char a; long b; }; // a:1, pad3, b:4 -> size 8 (max align 4, but pack 8 -> total multiple of 8)
struct S2 { char c; S1 d; long long e; };
// c: offset 0 (1)
// pad 3 -> offset 4
// d: offset 4 (size 8, align 4) -> occupies 4-11
// e: offset 12 -> needs 8 align -> pad 4 -> offset 16 (8 bytes)
// total 24 (multiple of 8)
#pragma pack()
#define __va_rounded_size(TYPE) \
(((sizeof(TYPE) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
// 等價位運算寫法:
#define __va_rounded_size(TYPE) \
((sizeof(TYPE) + sizeof(int) - 1) & ~(sizeof(int) - 1))
原理:sizeof(int)=4。將任意型別大小向上取整至 4 的倍數。對應 x86 呼叫慣例中參數在堆疊上以 4-byte 對齊推入。
sizeof(TYPE) >= 4 → (size+3)/4*4 向上取整。sizeof(TYPE) < 4 → (1+3)/4*4 = 4,char/short 亦佔 4 bytes。#pragma pack(1) 並手動處理對齊,確保跨平台一致。offsetof、static_assert (C11) 驗證佈局。long 可能 8 bytes (LP64),重新檢視對齊假設。