读取现代 C++ 中可能未对齐的字段

问题描述 投票:0回答:1

假设我有一个已知大小和偏移量的字段数据包,我想从中进行潜在的未对齐读取。在现代 C++ 中是否有比标准 memcpy 更符合人体工程学的方法来做到这一点? (请参阅此片段以了解我试图重新创建的行为)

根据我对

std::bit_cast
的了解,它似乎是一个合理的候选者,也许在像this这样的片段中,但是(A)这使用了
reinterpret_cast
并且(B)我不确定它是否是定义的行为
bit_cast
来自未对齐的地址。

c++17 bit-cast
1个回答
0
投票

在现代 C++ 中,尤其是 C++20 及更高版本,有多种方法可以比使用

std::memcpy
更符合人体工程学地执行未对齐读取,特别是如果您想避免与对齐和直接指针操作相关的潜在陷阱。

1.使用
std::bit_cast
(C++20)

std::bit_cast
允许您将对象的二进制表示重新解释为另一种类型。但是,您是正确的,
std::bit_cast
要求指针与其要转换的类型正确对齐。因此,它通常不是未对齐读取的合适候选者。

2.使用
std::array
或自定义结构

您可以考虑定义与您的数据布局相匹配的自定义结构。可以提高可读性和可维护性:

#include <array>
#include <iostream>
#include <cstring>

struct MyData {
    int value;

    // Assume more fields here...
};

int main() {
    char buf[500];
    std::memset(buf, '\0', sizeof(buf));

    MyData data;
    std::memcpy(reinterpret_cast<char*>(&data), &buf[213], sizeof(data));

    std::cout << data.value << std::endl;
}

这种方法封装了您的数据并使您的代码保持简洁。但是,它仍然使用

std::memcpy
,因此可能无法满足您避免直接内存操作的需求。

3.安全访问未对齐的数据

如果您需要使用未对齐的数据并避免

memcpy
,您也可以使用联合类型:

#include <iostream>
#include <cstring>

union AlignedUnion {
    int intValue;
    char byteArray[sizeof(int)];
};

int main() {
    char buf[500];
    std::memset(buf, '\0', sizeof(buf));
    
    AlignedUnion unalignedData;
    std::memcpy(unalignedData.byteArray, &buf[213], sizeof(int));
    
    std::cout << unalignedData.intValue << std::endl;
}

4.使用
std::span
(C++20)

使用C++20,您还可以将

std::span
与复制功能结合使用。这是一个简单的例子:

#include <array>
#include <iostream>
#include <span>
#include <cstring>

int main() {
    char buf[500];
    std::memset(buf, '\0', sizeof(buf));
    
    int x;
    std::span<char> s(&buf[213], sizeof(int));
    std::memcpy(&x, s.data(), sizeof(int));
    
    std::cout << x << std::endl;
}

结论

虽然

std::memcpy
是一种常见且通常合适的解决方案,但处理未对齐的访问可能很棘手并且存在潜在危险。如果您选择这样做,请始终确保您的目标体系结构支持未对齐访问。上述方法旨在简化您的代码,同时保持安全性和清晰度。

如果您绝对需要未对齐读取,则可能需要坚持使用

std::memcpy
或其他类似功能,同时注意特定于目标环境的对齐约束。

© www.soinside.com 2019 - 2024. All rights reserved.