CPU 訪問內存以字 (Word) 為單位 (32位機 4B,64位機 8B)。變量地址若為其大小的整數倍,單指令完成訪問;否則需兩次總線事務拼湊,嚴重影響性能,甚至觸發硬件異常 (某些架構)。編譯器自動插入填充字節滿足對齊。
min(成員大小, 編譯器對齊數) 的整數倍max(所有成員大小, 編譯器對齊數) 的整數倍
#pragma pack(4) // 顯式指定 4 字節對齊
struct Test {
char a; // 偏移 0,大小 1
short b; // 偏移 2 (2的倍數),大小 2
char c; // 偏移 4 (下一個 4 的倍數),大小 1
}; // 總大小 6 → 對齊到 4 的倍數 = 8
#pragma pack() // 恢復默認
// 佈局:
// offset 0: a (1B)
// offset 1: padding (1B)
// offset 2: b (2B)
// offset 4: c (1B)
// offset 5: padding (3B) → 總計 8B
struct __attribute__((aligned(4))) Test2 {
char a; // 1B
short b; // 2B
char c; // 1B
}; // 最大成員 2B,但強制整體 4B 對齊 → 總大小 8B (4的倍數)
// 佈局:
// a:0, pad:1, b:2-3, c:4, pad:5-7 → 8B
#pragma pack(1)
struct Packed {
char a; int b; char c;
}; // 大小 = 1+4+1 = 6B (無填充)
// 訪問 b 可能產生非對齊訪問,x86 允許但慢,ARM 可能崩潰
#pragma pack()
| 編譯器/平台 | 默認對齊數 | 控制方式 |
|---|---|---|
| GCC (Linux x86/x64) | 4 / 8 | #pragma pack(n), __attribute__((aligned(n))), __attribute__((packed)) |
| MSVC (Windows) | 8 | #pragma pack(n), __declspec(align(n)) |
| ARMCC / Clang | 4 / 8 | 同 GCC |
struct S {
type1 m1;
type2 m2;
...
};
// 1. 計算每個成員對齊要求 align_i = min(sizeof(type_i), 默認對齊數)
// 2. offset_1 = 0
// 3. offset_i = align_up(offset_{i-1} + sizeof(m_{i-1}), align_i)
// 4. 結構體對齊要求 S_align = max(align_i, 默認對齊數) [或 aligned(n) 指定]
// 5. 總大小 = align_up(offset_last + sizeof(last), S_align)
// 原序:24B (64位系統)
struct Bad {
char c; // 1B + 7B pad
double d; // 8B (offset 8)
int i; // 4B + 4B pad
short s; // 2B + 6B pad (總 24B)
};
// 優化序:16B
struct Good {
double d; // 8B (offset 0)
int i; // 4B (offset 8)
short s; // 2B (offset 12)
char c; // 1B (offset 14) + 1B pad → 16B
};
原則:按類型大小降序排列,大類型優先放置,減少填充。
unsigned int 4B):0 強制對齊到下一單元結構體對齊是空間換時間的經典權衡。掌握:
#pragma pack / aligned / packed 精確控制