假设我们得到一些数据作为字节序列,并想将该序列重新解释为一个结构(有一些保证数据确实是正确的格式)。例如:
#include <fstream>
#include <vector>
#include <cstdint>
#include <cstdlib>
#include <iostream>
struct Data
{
std::int32_t someDword[629835];
std::uint16_t someWord[9845];
std::int8_t someSignedByte;
};
Data* magic_reinterpret(void* raw)
{
return reinterpret_cast<Data*>(raw); // BAD! Breaks strict aliasing rules!
}
std::vector<char> getDataBytes()
{
std::ifstream file("file.bin",std::ios_base::binary);
if(!file) std::abort();
std::vector<char> rawData(sizeof(Data));
file.read(rawData.data(),sizeof(Data));
if(!file) std::abort();
return rawData;
}
int main()
{
auto rawData=getDataBytes();
Data* data=magic_reinterpret(rawData.data());
std::cout << "someWord[346]=" << data->someWord[346] << "\n";
data->someDword[390875]=23235;
std::cout << "someDword=" << data->someDword << "\n";
}
现在这里的magic_reinterpret
实际上是不好的,因为它违反了严格的别名规则,因此导致了UB。
它应该如何实现才不会导致 UB 并且不会像使用 memcpy
那样执行任何数据拷贝?
编辑:上面的getDataBytes()
函数实际上被认为是一些不可更改的函数。一个真实的例子是 ptrace(2)
,在 Linux 上,当 request==PTRACE_GETREGSET
和 addr==NT_PRSTATUS
时,写入(在 x86-64 上)两种不同大小的可能结构之一,具体取决于跟踪位数, 并返回大小。这里的 ptrace
调用代码在实际执行调用之前无法预测它将获得什么类型的结构。然后它如何安全地将它获得的结果重新解释为正确的指针类型?
最佳答案
不是将文件作为字节流读取,而是作为Data
结构流读取。
简单地做例如
Data data;
file.read(reinterpret_cast<char*>(&data), sizeof(data));
关于c++ - 如何在不导致 UB 的情况下将字节序列重新解释为 POD 结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34223438/