概述:C++結構體的`sizeof`不總是等於每個成員的`sizeof`之和,因為對齊和填充影響了記憶體佈局。未對齊的結構體可能存在間隙,而對齊的結構體會插入填充以保持對齊。通過示例展示了結構體的記憶體對齊和填充,以及如何使用模板元編程列印結構體成員的偏移量,深入理解記憶體佈局。 在C++中,結構體的si ...
概述:C++結構體的`sizeof`不總是等於每個成員的`sizeof`之和,因為對齊和填充影響了記憶體佈局。未對齊的結構體可能存在間隙,而對齊的結構體會插入填充以保持對齊。通過示例展示了結構體的記憶體對齊和填充,以及如何使用模板元編程列印結構體成員的偏移量,深入理解記憶體佈局。
在C++中,結構體的sizeof並不總是等於每個成員的sizeof之和,這是由於對齊和填充的影響。編譯器為了提高記憶體訪問速度,通常會在結構體成員之間插入一些填充位元組以對齊數據。
基礎功能:
示例源代碼:
#include <iostream>
// 未進行對齊的結構體
struct WithoutPadding {
char a; // 1 位元組
int b; // 4 位元組
char c; // 1 位元組
};
// 進行對齊的結構體
struct WithPadding {
char a; // 1 位元組
char padding[3]; // 對齊填充 3 位元組
int b; // 4 位元組
char c; // 1 位元組
};
int main() {
std::cout << "WithoutPadding 大小:" << sizeof(WithoutPadding) << std::endl;
std::cout << "WithPadding 大小:" << sizeof(WithPadding) << std::endl;
return 0;
}
在這個示例中,WithoutPadding 結構體的大小是 6 位元組(1 + 4 + 1),而WithPadding 結構體的大小是 12 位元組(1 + 3(填充)+ 4 + 1)。這是因為編譯器為了對齊int類型的成員b,在其前面插入了3位元組的填充。
高級功能:
示例源代碼:
#include <iostream>
#include <type_traits>
template <typename T>
void PrintOffsets() {
std::cout << "Offsets for " << typeid(T).name() << ":" << std::endl;
size_t offset = 0;
size_t size = sizeof(T);
// 使用模板元編程逐個列印成員的偏移量
// 對於 C++17,可以使用 std::is_standard_layout<T> 確保是標準佈局類型
if constexpr (std::is_standard_layout<T>::value) {
while (offset < size) {
std::cout << " Offset of member at index " << offset << ": " << offsetof(T, offset) << std::endl;
offset++;
}
} else {
std::cout << " Not a standard layout type." << std::endl;
}
std::cout << std::endl;
}
struct ExampleStruct {
char a; // 1 位元組
int b; // 4 位元組
char c; // 1 位元組
};
int main() {
PrintOffsets<ExampleStruct>();
return 0;
}
在這個示例中,PrintOffsets 函數使用模板元編程逐個列印結構體成員的偏移量。ExampleStruct 結構體包含了對齊填充,通過offsetof巨集可以獲取每個成員的偏移量。這有助於理解結構體記憶體佈局的細節。
通過這兩個示例,展示了結構體大小不等於成員sizeof之和的原因,以及如何使用模板元編程逐個列印結構體成員的偏移量。這些知識有助於理解記憶體對齊和結構體記憶體佈局。