阅读以下1和2问答,并使用下面讨论的技术多年来在x86架构上使用GCC和MSVC没有看到问题后,我现在非常困惑正确但同样重要的是以“最有效”的方式使用C ++序列化然后反序列化二进制数据。
给出以下“错误”代码:
int main()
{
std::ifstream strm("file.bin");
char buffer[sizeof(int)] = {0};
strm.read(buffer,sizeof(int));
int i = 0;
// Experts seem to think doing the following is bad and
// could crash entirely when run on ARM processors:
i = reinterpret_cast<int*>(buffer);
return 0;
}
现在我理解reinterpret_cast的作用是告诉编译器它可以将buffer中的内存视为整数,随后可以发出需要/假定某些数据对齐方式的整数兼容指令 - 唯一的开销是当CPU检测到它正在执行面向对齐方式的指令的地址实际上未对齐时,会产生额外的读取和移位。
尽管如此,以上提供的答案似乎表明就C ++而言,这都是未定义的行为。
假设从将进行转换的buffer位置的对齐方式不符合要求,则唯一的解决方案是逐个复制字节吗?是否有更有效的技术?
此外,多年来我看到过许多情况,其中完全由pod组成的结构体(使用编译器特定的pragma删除填充)被转换为char *,随后写入文件或套接字,然后稍后读回缓冲区并将缓冲区转换回原始结构体的指针,(忽略机器之间的潜在大小端和float / double格式问题),这种代码也被认为是未定义的行为吗?
以下是更复杂的示例:
int main()
{
std::ifstream strm("file.bin");
char buffer[1000] = {0};
const std::size_t size = sizeof(int) + sizeof(short) + sizeof(float) + sizeof(double);
const std::size_t weird_offset = 3;
buffer += weird_offset;
strm.read(buffer,size);
int i = 0;
short s = 0;
float f = 0.0f;
double d = 0.0;
// Experts seem to think doing the following is bad and
// could crash entirely when run on ARM processors:
i = reinterpret_cast<int*>(buffer);
buffer += sizeof(int);
s = reinterpret_cast<short*>(buffer);
buffer += sizeof(short);
f = reinterpret_cast<float*>(buffer);
buffer += sizeof(float);
d = reinterpret_cast<double*>(buffer);
buffer += sizeof(double);
return 0;
}