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

C 語言結構體內存對齊規則詳解:#pragma pack、屬性屬性、大小計算實戰

     編輯:關於C語言

為什麼要對齊?

CPU 訪問內存以字 (Word) 為單位 (32位機 4B,64位機 8B)。變量地址若為其大小的整數倍,單指令完成訪問;否則需兩次總線事務拼湊,嚴重影響性能,甚至觸發硬件異常 (某些架構)。編譯器自動插入填充字節滿足對齊。

對齊基本規則

  1. 成員對齊:每個成員偏移量為 min(成員大小, 編譯器對齊數) 的整數倍
  2. 結構體整體對齊:結構體總大小為 max(所有成員大小, 編譯器對齊數) 的整數倍
  3. 嵌套結構體:內層結構體按自身對齊要求放置,外層按最大對齊數對齊

實戰案例分析

案例 1:默認 4 字節對齊 (GCC x86)


#pragma pack(4)  // 顯式指定 4 字節對齊
struct Test {
    char a;      // 偏移 0,大小 1
    short b;     // 偏移 2 (2的倍數),大小 2
    char c;      // 偏移 4 (下一個 4 的倍數),大小 1
};               // 總大小 6 → 對齊到 4 的倍數 = 8
#pragma pack()   // 恢復默認

// 佈局:
// offset 0: a (1B)
// offset 1: padding (1B)
// offset 2: b (2B)
// offset 4: c (1B)
// offset 5: padding (3B) → 總計 8B

案例 2:強制 4 字節整體對齊 (__attribute__)


struct __attribute__((aligned(4))) Test2 {
    char a;      // 1B
    short b;     // 2B
    char c;      // 1B
};               // 最大成員 2B,但強制整體 4B 對齊 → 總大小 8B (4的倍數)

// 佈局:
// a:0, pad:1, b:2-3, c:4, pad:5-7 → 8B

案例 3:無對齊緊湊模式


#pragma pack(1)
struct Packed {
    char a; int b; char c;
}; // 大小 = 1+4+1 = 6B (無填充)
// 訪問 b 可能產生非對齊訪問,x86 允許但慢,ARM 可能崩潰
#pragma pack()

常見編譯器默認對齊數

編譯器/平台默認對齊數控制方式
GCC (Linux x86/x64)4 / 8#pragma pack(n), __attribute__((aligned(n))), __attribute__((packed))
MSVC (Windows)8#pragma pack(n), __declspec(align(n))
ARMCC / Clang4 / 8同 GCC

大小計算步驟速查表


struct S {
    type1 m1;
    type2 m2;
    ...
};

// 1. 計算每個成員對齊要求 align_i = min(sizeof(type_i), 默認對齊數)
// 2. offset_1 = 0
// 3. offset_i = align_up(offset_{i-1} + sizeof(m_{i-1}), align_i)
// 4. 結構體對齊要求 S_align = max(align_i, 默認對齊數) [或 aligned(n) 指定]
// 5. 總大小 = align_up(offset_last + sizeof(last), S_align)

優化技巧:成員重排減小體積


// 原序:24B (64位系統)
struct Bad {
    char c;      // 1B + 7B pad
    double d;    // 8B (offset 8)
    int i;       // 4B + 4B pad
    short s;     // 2B + 6B pad (總 24B)
};

// 優化序:16B
struct Good {
    double d;    // 8B (offset 0)
    int i;       // 4B (offset 8)
    short s;     // 2B (offset 12)
    char c;      // 1B (offset 14) + 1B pad → 16B
};

原則:按類型大小降序排列,大類型優先放置,減少填充。

位域對齊特殊規則

  • 位域不跨越其基礎類型邊界 (如 unsigned int 4B)
  • 相鄰位域嘗試壓緊排列,超出則換新單元
  • :0 強制對齊到下一單元

總結

結構體對齊是空間換時間的經典權衡。掌握:

  1. 成員偏移 = 對齊向上(前一成員末尾, 成員對齊要求)
  2. 總大小 = 對齊向上(最後成員末尾, 結構體對齊要求)
  3. 用 #pragma pack / aligned / packed 精確控制
  4. 成員重排可顯著減小體積 (嵌入式/大數組關鍵)
  5. 網絡協議/文件格式/硬件寄存器映射必須显式控制對齊確保跨平台一致
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved