**資料項只能存放在「其大小的整數倍」位址上。**
char (1B) → 任意位址short (2B) → 2 的倍數位址int/float (4B) → 4 的倍數位址double/long long/pointer(64bit) (8B) → 8 的倍數位址min(成員大小, n)。#include
struct BadOrder { char b; int a; int c; char d; }; // 16 bytes
struct GoodOrder { char b; char d; int a; int c; }; // 12 bytes
int main() {
struct BadOrder x; struct GoodOrder y;
printf("BadOrder : sizeof=%zu, b=%p a=%p c=%p d=%p\n",
sizeof(x), &x.b, &x.a, &x.c, &x.d);
printf("GoodOrder : sizeof=%zu, b=%p d=%p a=%p c=%p\n",
sizeof(y), &y.b, &y.d, &y.a, &y.c);
return 0;
}
/* 輸出範例:
BadOrder : sizeof=16, b=0x7ffe...e8 a=0x7ffe...ec c=0x7ffe...f0 d=0x7ffe...f4
GoodOrder : sizeof=12, b=0x7ffe...e8 d=0x7ffe...e9 a=0x7ffe...ec c=0x7ffe...f0
*/
結論:將小型別聚集、大型別聚集,可節省 25-50% 記憶體。
#pragma pack(4) // 最大對齊 4
struct Pack4 { char b; long long a; int c; char d; };
#pragma pack() // 恢復預設
// 輸出:a 位址可被 4 整除(非 8),sizeof=20(預設 8 對齊為 24)
// ⚠️ 代價:讀取 long long 可能觸發兩次總線週期,效能下降,甚至在某些架構(SPARC/ARM 舊核心)觸發 SIGBUS
| 平台/編譯器 | 預設最大對齊 | long 大小 | pointer 大小 | 長雙精度 |
|---|---|---|---|---|
| Windows MSVC (x86) | 8 | 4 | 4 | 8 (同 double) |
| Windows MSVC (x64) | 8 | 4 | 8 | 8 |
| Linux GCC (x86) | 4 | 4 | 4 | 12/16 |
| Linux GCC (x64) | 8 | 8 | 8 | 16 |
| ARM32 GCC | 4/8 | 4 | 4 | 8 |
| ARM64 GCC | 8 | 8 | 8 | 16 |
**GCC 特有規則**:__attribute__((aligned(n)))強制指定變數/結構體對齊;__attribute__((packed))等同#pragma pack(1)。
struct Inner { char c; int i; }; // sizeof=8 (預設 4 對齊)
struct Outer { char c; struct Inner i; }; // sizeof=16 而非 12!
// 原因:Inner 作為整體,其對齊需求為 max(alignof(char), alignof(int)) = 4
// Outer.c 佔 1 byte,需 3 byte padding 才能放 Inner (offset 4)
// Inner 佔 8 byte,Outer 總大小 12,但整體對齊需求 4 → 尾端補 4 byte → 16
// 解法:#pragma pack(4) 或重新排序成員
struct { unsigned a:1; unsigned b:3; } 壓縮布林/小整數。offsetof、sizeof、_Alignof (C11)、Clang -Wpadded 警告填充位元組。alignas(64) C++11 / __attribute__((aligned(64)))),避免偽共享。記憶體對齊是**空間換時間**的經典權衡。理解「成員對齊、整體對齊、pragma pack 上限」三大規則,善用 offsetof/sizeof 驗證,並以「大型別優先」原則排序成員,即可在不犧牲效能前提下,將結構體體積壓縮 20-40%。跨平台開發務必以 **GCC/Clang 屬性語法** 替代 #pragma pack,確保行為一致。