首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言結構體記憶體對齊完整指南:原理、計算、pragma pack 實戰

     編輯:關於C語言

為什麼要對齊

  • CPU 存取記憶體以「字」為單位 (32 位 = 4 字節,64 位 = 8 字節)
  • 未對齊存取需兩次總線週期讀取高低位拼湊,效能大幅下降
  • 某些架構 (SPARC, ARM 舊版) 未對齊直接觸發硬體異常

對齊基本規則

  1. 自身對齊值:`char=1`, `short=2`, `int/float=4`, `double=8` (視 ABI 而定)
  2. 指定對齊值:`#pragma pack(n)` 設定最大對齊邊界
  3. 有效對齊值 = `min(自身對齊值, 指定對齊值)`
  4. 成員偏移量 必須是有效對齊值的倍數
  5. 結構體總大小 必須是結構體有效對齊值 (所有成員中最大) 的倍數 (尾部填充)

經典範例分析


struct A { int a; char b; short c; }; // 4 + 1 + (1填充) + 2 = 8
struct B { char b; int a; short c; }; // 1 + (3填充) + 4 + 2 + (2填充) = 12

struct B 詳細佈局 (起始位址 0x0,預設 pack=4):

成員自身對齊有效對齊偏移量大小填充
b (char)110x010
a (int)440x443 (0x1-0x3)
c (short)220x820
結構體有效對齊 = max(1,4,2) = 4
當前大小 10,非 4 倍數 → 尾部填充 2 字節 → 總大小 12

#pragma pack 控制


#pragma pack(push)  // 保存當前狀態
#pragma pack(2)     // 最大對齊 2 字節
struct C { char b; int a; short c; }; // 大小 = 8
#pragma pack(pop)   // 恢復

#pragma pack(1)     // 緊密堆積
struct D { char b; int a; short c; }; // 大小 = 7 (無填充)
#pragma pack()

實戰案例:Intel/Microsoft 面試題


#pragma pack(8)
struct example1 { short a; long b; }; // short=2, long=4, max=4 → pack(8) 無效,實際 4
struct example2 { char c; example1 s; short e; };
#pragma pack()

// example1: a(0-1), 填充2, b(4-7) → size=8
// example2: c(0), 填充3, s(4-11), e(12-13), 尾部填充2 → size=16
// &example2.s - &example2 = 4

Union 對齊規則

  • Union 大小 = 最大成員大小 (向上取整至 Union 有效對齊值倍數)
  • Union 有效對齊值 = 所有成員有效對齊值最大值

union A { int a[5]; char b; double c; }; // 最大成員 double=8,但 int[5]=20
// 預設 pack=4 → double 對齊 4 → union 對齊 4
// 大小 = max(20, 1, 8) = 20 → 向上取整至 4 倍數 = 20? 實測 24 (編譯器常按最大成員對齊要求對齊整體)
// 實際:double 需 8 字節對齊 → union 對齊 8 → 大小 = 24 (20→24)

struct B { int n; union A u; char c[10]; };
// n(4), 填充4, u(24), c(10), 尾部填充6 → 總 48 (按 u 對齊 8)

最佳實踐建議

  1. 成員排序:按類型大小遞減排列 (大→小),減少填充。`double, int, short, char`
  2. 慎用 pack(1):省記憶體但犧牲存取速度,僅用於網路封包、檔案格式、硬體暫存器映射
  3. 跨平台:網路傳輸結構體必須用 `#pragma pack(1)` + 固定寬度型別 (`int32_t` 等) + 位序轉換 (`htonl`)
  4. 驗證工具:`offsetof` 巨集、`sizeof`、編譯器輸出佈局 (`-fdump-record-layouts` GCC/Clang)

標準引用

  • C11 §6.7.2.1 結構體/聯合體宣告
  • System V AMD64 ABI / Microsoft x64 ABI 文件 (平台具體對齊規則)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved