記憶體對齊可以用一句話概括:「資料項只能存儲在其大小整數倍的記憶體位址上」。例如 int 佔用 4 個位元組,其位址必須是 4 的倍數(0、4、8…)。這是硬體架構為了提升存取效率而施加的限制。
觀察以下結構體:
struct xx {
char b;
int a;
int c;
char d;
};
執行結果顯示:
&a = 0xffbff5ec
&b = 0xffbff5e8
&c = 0xffbff5f0
&d = 0xffbff5f4
sizeof(xx) = 16
b(1 位元組)位於 0xffbff5e8a(4 位元組)必須 4 位元組對齊,因此跳過 3 位元組,存放在 0xffbff5ecc 緊接在 a 之後d 佔 1 位元組,但結構體總大小為 16,因為結構體本身也要滿足最大成員(4 位元組)的對齊,尾部補齊 3 位元組調整成員順序,將相同大小的類型集中:
struct xx {
char b;
char d;
int a;
int c;
};
此時 sizeof(xx) = 12,節省 4 位元組。實際開發中,合理排序結構體成員能有效減少記憶體佔用。
#pragma pack各作業系統有預設對齊係數(現代系統通常為 8)。當預設係數小於資料類型大小時,以預設係數為準。可用 #pragma pack(n) 暫時修改:
#pragma pack(4)
struct xx {
char b;
long long a; // 8 位元組,但受限於 pack(4) 僅 4 位元組對齊
int c;
char d;
};
#pragma pack()
建議:除非特殊需求(如網路協議、硬體映射),否則不要隨意修改預設對齊,否則可能導致效能下降或跨平台問題。
CPU 讀取記憶體以「塊」為單位(通常等於預設對齊係數)。若資料跨越兩個塊,CPU 需發起兩次總線讀取並拼合,嚴重降低效能。對齊確保單次讀取即可取得完整資料。
| 類型 | MSVC (Windows) | GCC (Linux) |
|---|---|---|
| char | 1 | 1 |
| short | 2 | 2 |
| int/long | 4 | 4 |
| long long/double | 8 | 4 |
同樣的結構體在兩平台大小可能不同,跨平台開發需特別注意。
外層結構體必須確保內層結構體起始位址滿足其對齊需求,必要時插入填充位元組。
位欄行為複雜且編譯器相關性強,建議僅在極度受限的資源環境使用。
static_assert 驗證結構體大小