这些结构的大小在文件中不同但在程序内存中相同
The size of these structs are different in a file but the same in program memory
考虑以下 POD 结构:
struct MessageWithArray {
uint32_t raw;
uint32_t myArray[10];
//MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } { };
};
运行 以下:
#include <type_traits>
#include <iostream>
#include <fstream>
#include <string>
struct MessageWithArray {
uint32_t raw;
uint32_t myArray[10];
//MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } { };
};
//
template <class T>
char* as_bytes(T& x) {
return &reinterpret_cast<char&>(x);
// or:
// return reinterpret_cast<char*>(std::addressof(x));
}
int main() {
MessageWithArray msg = { 0, {0,1,2,3,4,5,6,7,8,9} };
std::cout << "Size of MessageWithArray struct: " << sizeof(msg) << std::endl;
std::cout << "Is a POD? " << std::is_pod<MessageWithArray>() << std::endl;
std::ofstream buffer("message.txt");
buffer.write(as_bytes(msg), sizeof(msg));
return 0;
}
给出以下输出:
Size of MessageWithArray struct: 44
Is a POD? 1
"message.txt" 文件的十六进制转储如下所示:
00 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00
03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00
07 00 00 00 08 00 00 00 09 00 00 00
现在,如果我取消对构造函数的注释(以便 MessageWithArray
具有零参数构造函数),MessageWithArray
将成为非 POD 结构。然后我使用构造函数来初始化。这导致代码发生以下变化:
....
struct MessageWithArray {
.....
MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 }{ };
};
....
int main(){
MessageWithArray msg;
....
}
运行这段代码,我得到:
Size of MessageWithArray struct: 44
Is a POD? 0
"message.txt" 文件的十六进制转储如下所示:
00 00 00 00 0D 0A 00 00 00 14 00 00 00 1E 00 00
00 28 00 00 00 32 00 00 00 3C 00 00 00 46 00 00
00 50 00 00 00 5A 00 00 00 64 00 00 00
现在,我对实际的十六进制值不太感兴趣,我很好奇的是 为什么与 POD 结构转储相比,非 POD 结构转储中多了一个字节,当 sizeof() 声明它们的字节数相同时?是否有可能,因为构造函数使结构成为非 POD,所以隐藏的东西已添加到结构中? sizeof() 应该是准确的编译时检查,对吗?是否有可能避免被 sizeof() 测量?
规格:我是运行这个在Visual Studio2017版本15.7.5,Microsoft Visual C++ 2017的一个空项目中,在Windows 10台机器。
英特尔酷睿 i7-4600M CPU
64 位操作系统,基于 x64 的处理器
编辑:我决定初始化结构以避免未定义的行为,因为这个问题在初始化时仍然有效。将其初始化为不带 10 的值会保留我最初观察到的行为,因为数组中的数据从未包含任何 10(即使它是垃圾,而且是随机的)。
与POD-ness无关。
您的 ofstream
是以文本模式(而不是二进制模式)打开的。在 windows 上,这意味着 \n
被转换为 \r\n
。
在第二种情况下,结构中恰好有一个0x0A
(\n
)字节,变成了0x0D 0x0A
(\r\n
)。这就是为什么您会看到一个额外的字节。
此外,在第一种情况下使用未初始化的变量会导致未定义的行为,而这种情况并没有表现出来。
其他答案解释了将二进制数据写入以文本模式打开的流的问题,但是这段代码根本上是错误的。不需要转储任何东西,检查这些结构的大小并验证它们是否相等的正确方法是使用 static_assert
:
struct MessageWithArray {
uint32_t raw;
uint32_t myArray[10];
};
struct NonPodMessageWithArray {
uint32_t raw;
uint32_t myArray[10];
NonPodMessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } {}
};
static_assert(sizeof(MessageWithArray) == sizeof(NonPodMessageWithArray));
考虑以下 POD 结构:
struct MessageWithArray {
uint32_t raw;
uint32_t myArray[10];
//MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } { };
};
运行 以下:
#include <type_traits>
#include <iostream>
#include <fstream>
#include <string>
struct MessageWithArray {
uint32_t raw;
uint32_t myArray[10];
//MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } { };
};
//
template <class T>
char* as_bytes(T& x) {
return &reinterpret_cast<char&>(x);
// or:
// return reinterpret_cast<char*>(std::addressof(x));
}
int main() {
MessageWithArray msg = { 0, {0,1,2,3,4,5,6,7,8,9} };
std::cout << "Size of MessageWithArray struct: " << sizeof(msg) << std::endl;
std::cout << "Is a POD? " << std::is_pod<MessageWithArray>() << std::endl;
std::ofstream buffer("message.txt");
buffer.write(as_bytes(msg), sizeof(msg));
return 0;
}
给出以下输出:
Size of MessageWithArray struct: 44
Is a POD? 1
"message.txt" 文件的十六进制转储如下所示:
00 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00
03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00
07 00 00 00 08 00 00 00 09 00 00 00
现在,如果我取消对构造函数的注释(以便 MessageWithArray
具有零参数构造函数),MessageWithArray
将成为非 POD 结构。然后我使用构造函数来初始化。这导致代码发生以下变化:
....
struct MessageWithArray {
.....
MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 }{ };
};
....
int main(){
MessageWithArray msg;
....
}
运行这段代码,我得到:
Size of MessageWithArray struct: 44
Is a POD? 0
"message.txt" 文件的十六进制转储如下所示:
00 00 00 00 0D 0A 00 00 00 14 00 00 00 1E 00 00
00 28 00 00 00 32 00 00 00 3C 00 00 00 46 00 00
00 50 00 00 00 5A 00 00 00 64 00 00 00
现在,我对实际的十六进制值不太感兴趣,我很好奇的是 为什么与 POD 结构转储相比,非 POD 结构转储中多了一个字节,当 sizeof() 声明它们的字节数相同时?是否有可能,因为构造函数使结构成为非 POD,所以隐藏的东西已添加到结构中? sizeof() 应该是准确的编译时检查,对吗?是否有可能避免被 sizeof() 测量?
规格:我是运行这个在Visual Studio2017版本15.7.5,Microsoft Visual C++ 2017的一个空项目中,在Windows 10台机器。
英特尔酷睿 i7-4600M CPU 64 位操作系统,基于 x64 的处理器
编辑:我决定初始化结构以避免未定义的行为,因为这个问题在初始化时仍然有效。将其初始化为不带 10 的值会保留我最初观察到的行为,因为数组中的数据从未包含任何 10(即使它是垃圾,而且是随机的)。
与POD-ness无关。
您的 ofstream
是以文本模式(而不是二进制模式)打开的。在 windows 上,这意味着 \n
被转换为 \r\n
。
在第二种情况下,结构中恰好有一个0x0A
(\n
)字节,变成了0x0D 0x0A
(\r\n
)。这就是为什么您会看到一个额外的字节。
此外,在第一种情况下使用未初始化的变量会导致未定义的行为,而这种情况并没有表现出来。
其他答案解释了将二进制数据写入以文本模式打开的流的问题,但是这段代码根本上是错误的。不需要转储任何东西,检查这些结构的大小并验证它们是否相等的正确方法是使用 static_assert
:
struct MessageWithArray {
uint32_t raw;
uint32_t myArray[10];
};
struct NonPodMessageWithArray {
uint32_t raw;
uint32_t myArray[10];
NonPodMessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } {}
};
static_assert(sizeof(MessageWithArray) == sizeof(NonPodMessageWithArray));