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

C/C++ 內存對齊詳解:結構體大小計算與 #pragma pack 控制

     編輯:關於C++

對象內存佔用組成

類對象大小 = 非靜態成員變量總和 + 編譯器為 CPU 訪問效率插入的填充字節 + 虛函數表指針(如有虛函數)。

本文聚焦數據對齊填充規則。

無 #pragma pack 時的三大對齊規則

規則 1:成員對齊

第一個成員偏移量為 0。後續成員偏移量必須是該成員大小的整數倍。32 位系統下 int 4 字節,偏移量為 4 的倍數;double 8 字節,偏移量為 8 的倍數。

規則 2:嵌套結構體對齊

結構體作為成員時,其起始偏移量必須是內部最大成員大小的整數倍。如內部含 double(8 字節),則外部結構體中該成員偏移量為 8 的倍數。

規則 3:整體大小對齊

結構體總大小必須是所有成員中最大類型大小的整數倍(嵌套結構體按其內部最大成員算)。不足時尾部填充。

範例演示

範例 1:基本類型

struct A {
    char a;      // 偏移 0,大小 1
    // 填充 7 字節 (對齊 double)
    double b;    // 偏移 8,大小 8
    int c;       // 偏移 16,大小 4
    // 填充 4 字節 (整體對齊 8)
};  // sizeof(A) = 24

範例 2:嵌套結構體

struct B {
    int a;       // 偏移 0,大小 4
    // 填充 4 字節 (對齊 A 的最大成員 double=8)
    A b;         // 偏移 8,大小 24
    char c;      // 偏移 32,大小 1
    // 填充 7 字節 (整體對齊 8)
};  // sizeof(B) = 40

#pragma pack(n) 控制對齊

#pragma pack(n) 指定按 n 字節對齊。實際對齊數 = min(成員自身對齊數, n)。

  • n=1:取消對齊,緊湊排列
  • n=4:double 按 4 字節對齊而非 8
  • #pragma pack():恢復默認對齊

範例:#pragma pack(4)

#pragma pack(4)
struct C {
    char a;      // 偏移 0
    double b;    // 偏移 4 (min(8,4)=4)
    int c;       // 偏移 12
};  // sizeof(C) = 16 (max align=4)
#pragma pack()

實際驗證代碼

#include 
using namespace std;

struct A { char a; double b; int c; };
struct B { int a; A b; char c; };

int main() {
    cout << "sizeof(A) = " << sizeof(A) << endl;  // 24
    cout << "sizeof(B) = " << sizeof(B) << endl;  // 40
    
    A obj;
    cout << "&obj.a = " << (void*)&obj.a << endl;
    cout << "&obj.b = " << (void*)&obj.b << endl;
    cout << "&obj.c = " << (void*)&obj.c << endl;
    return 0;
}

為什麼需要對齊?

  1. CPU 訪問效率:大多數 CPU 要求數據地址對齊(如 4 字節整數地址為 4 的倍數),否則需兩次總線週期讀取,甚至觸發硬件異常
  2. 原子操作支持:對齊是原子讀寫的前提
  3. 緩存行優化:避免跨緩存行訪問

最佳實踐建議

  1. 成員按大小排序:大類型在前,小類型在後,減少填充(如 double, int, char)
  2. 謹慎使用 #pragma pack:除非嵌入式/網絡協議/文件格式強制要求,否則保持默認對齊
  3. 關注關鍵路徑結構體:高頻訪問的結構體優化佈局可提升緩存命中率
  4. 使用 offsetof 驗證:offsetof(Struct, member) 獲取成員偏移量

總結

內存對齊是 C/C++ 為換取 CPU 訪問效率而引入的編譯器行為。理解三大規則(成員、嵌套、整體)能準確預測 sizeof 結果。#pragma pack 提供控制手段,但除非有明確跨平台二進制兼容需求,一般不建議修改默認對齊。

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