現代 CPU 從內存讀取數據時,若地址滿足特定邊界條件(如 4 字節整數地址能被 4 整除),可單周期完成;否則需多周期拼湊,嚴重降低效率。編譯器自動插入填充字節,使結構體成員滿足對齊要求。
| 優勢 | 代價 |
|---|---|
| CPU 訪問效率最高(單周期) | 內存佔用增加(填充字節) |
| 部分架構(SPARC)強制要求,否則硬件異常 | 結構體大小非直觀,易導致序列化不一致 |
| 原子操作、SIMD 指令要求對齊 | 跨平台傳輸需約定相同對齊策略 |
char=1, short=2, int/long/float/ptr=4, long long/double=8(32 位)#pragma pack(n) 指定,n 為 1/2/4/8/16min(自身對齊值, 指定對齊值, 默認對齊值)放置規則:成員按聲明順序,起始地址滿足 offset % N == 0。結構體總大小須為有效對齊值的整數倍(尾部填充)。
struct B {
char b; // offset 0, size 1
int a; // offset 4 (對齊 4), size 4
short c; // offset 8 (對齊 2), size 2
}; // 總佔用 0x0000~0x000B = 12 字節
結構體自身對齊=4,尾部填充 2 字節至 12(4 的倍數)。
#pragma pack(2) 指定 2 字節對齊#pragma pack(2)
struct C {
char b; // offset 0, size 1
int a; // offset 2 (有效對齊 min(4,2)=2), size 4
short c; // offset 6 (對齊 2), size 2
};
#pragma pack()
總大小 8 字節(8%2==0,無尾部填充)。
#includestruct A { char c; short s; int i; }; #pragma pack(1) struct PA { char c; short s; int i; }; #pragma pack() struct B { char c; int i; short s; }; #pragma pack(2) struct PB { char c; int i; short s; }; #pragma pack() int main() { struct A a; struct PA pa; struct B b; struct PB pb; printf("sizeof(A) = %zu, &c=%p &s=%p &i=%p\n", sizeof(a), &a.c, &a.s, &a.i); printf("sizeof(PA) = %zu, &c=%p &s=%p &i=%p\n", sizeof(pa), &pa.c, &pa.s, &pa.i); printf("sizeof(B) = %zu, &c=%p &s=%p &i=%p\n", sizeof(b), &b.c, &b.s, &b.i); printf("sizeof(PB) = %zu, &c=%p &s=%p &i=%p\n", sizeof(pb), &pb.c, &pb.s, &pb.i); return 0; }

圖 輸出結果驗證理論計算
#pragma pack(1) 或屬性 __attribute__((packed))htons/htonl/ntohs/ntohllong/指針 8 字節,結構體大小可能與 32 位不同字節對齊是「空間換時間」的經典體現。理解 有效對齊值 = min(自身, 指定, 默認) 並能手算偏移,是 C 程序員進階必備技能。跨平台項目中,統一對齊策略與字節序處理,能避免 90% 的詭異 Bug。