sizeof
是 C++ 中的一個編譯時運算符,用于獲取對象或類型所占的字節數(以 size_t
返回)。它是掌握底層內存模型、結構體對齊、數組大小計算等的重要工具。
1. 基本語法
sizeof(type) // 獲取類型的大小
sizeof expression // 獲取表達式結果的大小
2. 返回值類型
sizeof
返回類型是std::size_t
(定義在<cstddef>
中),是一個無符號整型,足以容納系統中對象的最大可能大小。
3. 示例代碼一覽
#include <iostream>
#include <cstddef>int main() {int a = 5;double b = 3.14;int arr[10];std::cout << "sizeof(int): " << sizeof(int) << "\n";std::cout << "sizeof(a): " << sizeof(a) << "\n";std::cout << "sizeof(b): " << sizeof b << "\n"; // 可省略括號std::cout << "sizeof(arr): " << sizeof(arr) << "\n";std::cout << "Number of elements in arr: " << sizeof(arr) / sizeof(arr[0]) << "\n";return 0;
}
4. 結構體對齊示例(含填充字節)
#include <iostream>struct A {char c; // 1 byteint i; // 4 bytes
};int main() {std::cout << "sizeof(char): " << sizeof(char) << "\n";std::cout << "sizeof(int): " << sizeof(int) << "\n";std::cout << "sizeof(A): " << sizeof(A) << "\n"; // likely 8 due to padding
}
結構體
A
實際大小常常為 8,而不是 5,這是因為編譯器插入了填充字節以保證成員變量對齊(稱為結構體對齊或 padding)。
5. 指針和數組的區別
int arr[10];
int* p = arr;std::cout << "sizeof(arr): " << sizeof(arr) << "\n"; // 10 * sizeof(int)
std::cout << "sizeof(p): " << sizeof(p) << "\n"; // 指針大小,通常是 8(64 位系統)
6. 類的 sizeof
示例(含虛函數、繼承)
#include <iostream>class Base {virtual void foo() {}
};class Derived : public Base {int data;
};int main() {std::cout << "sizeof(Base): " << sizeof(Base) << "\n"; // 有 vptr,通常為 8std::cout << "sizeof(Derived): " << sizeof(Derived) << "\n"; // vptr + int + padding
}
7. 注意事項
事項 | 說明 |
---|---|
sizeof 是編譯時運算 | 除非作用于 VLA(C99 風格,C++ 不支持),否則計算在編譯期完成 |
對于類型無需括號 | sizeof expression 中括號可省;sizeof(type) 中必須加括號 |
數組退化 | sizeof(arr) 在函數參數中為指針大小,不是數組總大小 |
對動態分配數組無效 | sizeof(new int[10]) 得到的是指針大小,不是數組大小 |
8. sizeof
與模板配合(常用于靜態斷言)
template<typename T>
void check_size() {static_assert(sizeof(T) <= 8, "Type is too big!");
}
9. C++11 起的 alignof
#include <iostream>
#include <type_traits>struct MyStruct {char c;double d;
};int main() {std::cout << "sizeof(MyStruct): " << sizeof(MyStruct) << "\n";std::cout << "alignof(MyStruct): " << alignof(MyStruct) << "\n";
}
10、綜合示例
下面是一個 跨平臺結構體對齊測試工具類 的完整示例,功能如下:
- 顯示結構體每個成員的偏移量(
offsetof
); - 顯示結構體整體
sizeof
和alignof
; - 兼容 GCC / Clang / MSVC;
- 可用于診斷因字節對齊(padding)帶來的內存浪費。
工具類:StructInspector
功能說明:
- 使用
offsetof
獲取成員偏移; - 使用
sizeof
和alignof
獲取結構體大小和對齊; - 可擴展支持任意結構體(通過宏注冊成員)。
示例代碼
#include <iostream>
#include <iomanip>
#include <cstddef>
#include <string>
#include <type_traits>// 通用格式輸出宏
#define PRINT_ALIGN_INFO(T) \std::cout << "Struct: " << #T << "\n" \<< " Size: " << sizeof(T) << "\n" \<< " Alignof: " << alignof(T) << "\n\n";// 檢查偏移宏(成員名必須為字符串形式)
#define PRINT_MEMBER_OFFSET(StructType, Member) \std::cout << std::setw(20) << #Member << " @ offset: " << offsetof(StructType, Member) << "\n";// -----------------------------
// 示例結構體
// -----------------------------
struct MyStruct {char c1;double d;int i;char c2;
};struct PackedStruct {char c1;char c2;int i;
} __attribute__((packed)); // GCC/Clang 特性(MSVC: use #pragma pack)#pragma pack(push, 1)
struct MsvcPackedStruct {char c1;char c2;int i;
};
#pragma pack(pop)// -----------------------------
// 工具函數:打印結構體布局
// -----------------------------
template<typename T>
void InspectStructLayout(const std::string& name) {std::cout << "==============================\n";std::cout << "Inspecting: " << name << "\n";std::cout << "sizeof(" << name << ") = " << sizeof(T) << "\n";std::cout << "alignof(" << name << ") = " << alignof(T) << "\n";std::cout << "------------------------------\n";
}// 示例專用模板:打印具體成員偏移
void Inspect_MyStruct() {InspectStructLayout<MyStruct>("MyStruct");PRINT_MEMBER_OFFSET(MyStruct, c1);PRINT_MEMBER_OFFSET(MyStruct, d);PRINT_MEMBER_OFFSET(MyStruct, i);PRINT_MEMBER_OFFSET(MyStruct, c2);std::cout << "\n";
}void Inspect_PackedStruct() {InspectStructLayout<PackedStruct>("PackedStruct");PRINT_MEMBER_OFFSET(PackedStruct, c1);PRINT_MEMBER_OFFSET(PackedStruct, c2);PRINT_MEMBER_OFFSET(PackedStruct, i);std::cout << "\n";
}void Inspect_MsvcPackedStruct() {InspectStructLayout<MsvcPackedStruct>("MsvcPackedStruct");PRINT_MEMBER_OFFSET(MsvcPackedStruct, c1);PRINT_MEMBER_OFFSET(MsvcPackedStruct, c2);PRINT_MEMBER_OFFSET(MsvcPackedStruct, i);std::cout << "\n";
}// -----------------------------
// 主程序入口
// -----------------------------
int main() {Inspect_MyStruct();Inspect_PackedStruct();Inspect_MsvcPackedStruct();return 0;
}
示例輸出(Linux + GCC)
==============================
Inspecting: MyStruct
sizeof(MyStruct) = 24
alignof(MyStruct) = 8
------------------------------c1 @ offset: 0d @ offset: 8i @ offset: 16c2 @ offset: 20==============================
Inspecting: PackedStruct
sizeof(PackedStruct) = 6
alignof(PackedStruct) = 1
------------------------------c1 @ offset: 0c2 @ offset: 1i @ offset: 2==============================
Inspecting: MsvcPackedStruct
sizeof(MsvcPackedStruct) = 6
alignof(MsvcPackedStruct) = 1
------------------------------c1 @ offset: 0c2 @ offset: 1i @ offset: 2
可擴展功能
可以封裝為模板工具類,如下:
template<typename T>
struct StructAnalyzer {static void inspect(const std::vector<std::string>& member_names, const std::vector<std::size_t>& member_offsets) {std::cout << "Sizeof: " << sizeof(T) << ", Alignof: " << alignof(T) << "\n";for (size_t i = 0; i < member_names.size(); ++i)std::cout << member_names[i] << " @ offset: " << member_offsets[i] << "\n";}
};
因為 C++ 不支持反射,需要手動提供成員名與偏移。
小結
功能 | 實現 |
---|---|
成員偏移計算 | offsetof(StructType, member) |
結構體大小與對齊 | sizeof , alignof |
跨平臺結構體分析支持 | __attribute__((packed)) / #pragma pack(1) |
填充字節檢查(診斷浪費) | offsetof + sizeof 分析對比 |
總結
用法 | 說明 |
---|---|
sizeof(type) | 獲取某個類型的大小 |
sizeof(expr) | 獲取表達式類型的大小 |
獲取數組元素個數 | sizeof(arr) / sizeof(arr[0]) |
獲取結構體大小(含對齊) | sizeof(Struct) |
與模板、static_assert 配合 | 編譯時類型檢查 |
指針大小 | 與指向對象大小無關 |