c++ - 如何在不导致 UB 的情况下将字节序列重新解释为 POD 结构?

标签 c++ struct undefined-behavior strict-aliasing

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

#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_GETREGSETaddr==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/

相关文章:

c++ - 按输出窗口后 Xcode 6 意外退出

c++ - 区分 C++ 中标记化字符串中的操作数和运算符

c++ - 未解析为候选容器的模板运算符模板

c# - 关键字 "new"对 C# 中的结构有何作用?

c - 类型 "void"的值不能分配给类型为“void(*)(struct *Queue, int) 的实体”

c++ - 在类定义之外的模板类成员函数主体中,何时需要模板参数?

C 结构数据在迭代循环外无法保持一致

c - 将变量作为参数进行比较的 printf 的说明

c - 我应该采取什么预防措施来制作不调用未定义行为的内存池?

c++ - C++ 中转换为 simd 类型是未定义行为吗?