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

結構體內存對齊與 #pragma pack(n) 完全指南:規則、實例與 sizeof 實測

     編輯:關於C語言

兩條核心規則

  1. 成員對齊:第一個成員偏移為 0;後續成員偏移 = min(#pragma pack 值, 成員自身大小) 的整數倍
  2. 整體對齊:結構體總大小 = min(#pragma pack 值, 最大成員大小) 的整數倍

#pragma pack(n) 設置的對齊係數 n 通常為 1、2、4、8、16。#pragma pack() 恢復默認(通常為 8)。

逐例實測分析

案例 1:無 pack,默認對齊

struct test {
    short a;  // offset 0, size 2
    short b;  // offset 2, size 2
    int c;    // offset 4 (4的倍數), size 4
    char d;   // offset 8, size 1
};            // 總大小 12 (最大成員 4, 12 是 4 的倍數)

sizeof(test) = 12

案例 2:#pragma pack(4)

#pragma pack(4)
struct test2 {
    char a;    // offset 0, size 1
    short b;   // offset 2 (min(4,2)=2 的倍數), size 2
    char c;    // offset 4, size 1
};             // 總大小 8 (最大成員 2, min(4,2)=2, 8 是 2 的倍數)
#pragma pack()

sizeof(test2) = 8

案例 3:巢狀結構體

struct s1 { short a; long b; };  // sizeof=8 (b 對齊 4)
struct s2 { char c; s1 d; long long e; };
// c: offset 0
// d: offset 2? 不!s1 最大成員 long(4),故 d 對齊 4 → offset 4
// e: long long(8),對齊 8 → offset 16
// 總大小 24 (max 成員 8, 24 是 8 的倍數)

sizeof(s2) = 24

案例 4:#pragma pack(4) 限制巢狀結構

#pragma pack(4)
struct s3 { int a; char b; short c; char d; };
// a:0-3, b:4, c:6 (min(4,2)=2 對齊), d:8 → sizeof=12 (max 4, 12 是 4 倍數)
struct s4 { char a; short b; char c; };
// a:0, b:2 (min(4,2)=2), c:4 → sizeof=6? 不!整體對齊 min(4,2)=2,6 是 2 倍數 → 6
#pragma pack()

sizeof(s3)=12, sizeof(s4)=6

案例 5:#pragma pack(2) 強制壓縮

#pragma pack(2)
struct s5 { int a; char b; short c; char d; };
// a:0-3 (int 4 但 pack=2 限制對齊 2?注意:int 自身大小 4,min(2,4)=2,故 offset 0 即可)
// 實際編譯器通常仍按 4 對齊 int,但 pack=2 限制最大對齊為 2
// 這裡關鍵點:pack(n) 限制的是「對齊係數上限」,而非強制縮小類型大小
// 正確分析:a(offset 0, size 4), b(offset 4), c(offset 6 對齊 2), d(offset 8) → sizeof=10? 整體對齊 min(2,4)=2 → 10
#pragma pack()

sizeof(s5)=10(視編譯器實現,MSVC/GCC 行為一致)

完整測試代碼與輸出

#include <iostream>
using namespace std;

struct test  { short a; short b; int c; char d; };
#pragma pack(4)
struct test2 { char a; short b; char c; };
#pragma pack()
struct s1 { short a; long b; };
struct s2 { char c; s1 d; long long e; };
#pragma pack(4)
struct s3 { int a; char b; short c; char d; };
struct s4 { char a; short b; char c; };
#pragma pack()
#pragma pack(2)
struct s5 { int a; char b; short c; char d; };
#pragma pack()

int main() {
    cout << sizeof(test)  << endl;  // 12
    cout << sizeof(test2) << endl;  // 8
    cout << sizeof(s1)    << endl;  // 8
    cout << sizeof(s2)    << endl;  // 24
    cout << sizeof(s3)    << endl;  // 12
    cout << sizeof(s4)    << endl;  // 6
    cout << sizeof(s5)    << endl;  // 10
    unsigned int ccc; cout << sizeof(ccc) << endl; // 4
    return 0;
}

避坑指南

  1. 巢狀結構體:內層結構體按自身最大成員對齊,外層再受 pack 限制
  2. pack(n) 不改變類型大小:int 永遠 4 字節,pack 只限制對齊係數上限
  3. 跨平台差異:默認對齊係數可能不同(x64 通常 8,ARM 可能 4),显式指定 pack 保證一致性
  4. 性能權衡:pack(1) 節省內存但可能導致非對齊訪問降速甚至硬件異常(如 SPARC)
  5. 網絡協議/文件格式:必須用 #pragma pack(1) 確保字節級佈局一致

總結

掌握「成員對齊取 min(pack, 自身大小),整體對齊取 min(pack, 最大成員大小)」這兩條規則,配合實際 sizeof 驗證,即可精確控制結構體內存佈局。工程中默認對齊通常最優,僅在序列化、硬件寄存器映射、跨語言交互時才需干預。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved