在 C 語言中,位元組對齊是指變數在記憶體中的起始位址必須是其佔用位元組數的整數倍。具體來說,若一個變數佔用 n 個位元組,則其起始位址必須滿足 起始位址 % n = 0。對於結構體而言,n 取其成員中佔用空間最大的資料類型大小。
雖然記憶體空間以位元組為單位劃分,理論上可從任意位址訪問,但不同 CPU 架構為了提高記憶體訪問速度,規定特定類型的資料只能從特定起始位置訪問。這導致各類資料必須按規則存放,而非單純順序排列。
以 32 位系統為例:若 int 型(4 位元組)存放在偶數位址,CPU 只需一個讀取週期即可讀出;若存放在奇數位址,則需兩個讀取週期並拼湊高低位元組,明顯降低效率。
對齊過程遵循兩大核心原則:
#pragma pack(value))中較小者對齊。自身對齊值通常等於類型大小:char 為 1、short 為 2、int/long/float 為 4、double 為 8。假設 #pragma pack(8),分析以下結構體:
struct A { char a; long b; };
char a:自身對齊值 1,位址 0x0000 滿足對齊。long b:自身對齊值 4,0x0001 不滿足,補 3 位元組空位,從 0x0004 開始存放,佔 4 位元組。a*** b,sizeof(struct A) = 8。更複雜的巢狀結構體 struct B { char a; struct A b; long c; }:
char a:位址 0x0000。struct A b:自身對齊值 4,補 3 位元組,從 0x0004 開始,佔 8 位元組(至 0x000B)。long c:下一位址 0x000C 滿足 4 位元組對齊,佔 4 位元組(至 0x000F)。a*** b c,sizeof = 16。引入 double(對齊值 8)的 struct C 則會觸發更多填充,導致 sizeof = 24。調整成員宣告順序(如 struct E 將 int 置於 struct A 之前)可減少填充,sizeof 從 32 降至 24。
reserved 成員(如 char reserved[3];),提高程式碼可讀性並預留擴展空間。#pragma pack 控制對齊,但需注意跨平台一致性,網路傳輸結構體時雙端必須約定相同對齊方式。掌握對齊機制不僅能避免 sizeof 結果出乎意料,更能編寫高效、可移植的系統級程式碼。