如何在不引起UB的情况下将字节序列重新解释为POD结构?

Rus*_*lan 7 c++ struct strict-aliasing undefined-behavior

假设我们将一些数据作为一个字节序列获得,并希望将该序列重新解释为一个结构(有一些保证数据确实是正确的格式).例如:

#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";
}
Run Code Online (Sandbox Code Playgroud)

现在magic_reinterpret这里实际上是坏的,因为它打破了严格的别名规则,从而导致UB.

它应该如何实现不会导致UB而不执行任何数据副本memcpy


编辑:getDataBytes()上面的函数实际上被认为是一些不可改变的功能.一个真实的例子是ptrace(2),在Linux上,何时request==PTRACE_GETREGSETaddr==NT_PRSTATUS(根据x86-64)写入两种不同大小的结构中的一种,具体取决于跟踪位数,并返回大小.这里ptrace调用代码无法预测它实际执行调用之前将获得的结构类型.那怎么能安全地重新解释它得到的结果作为正确的指针类型?

Som*_*ude 4

不将文件作为字节流读取,而是作为Data结构流读取。

只需做例如

Data data;
file.read(reinterpret_cast<char*>(&data), sizeof(data));
Run Code Online (Sandbox Code Playgroud)