从 char* 缓冲区读取int32_t的惯用 cpp14 方法是什么?

What is the idiomatic cpp14 way to read an int32_t from a char* buffer?

本文关键字:cpp14 方法 是什么 char 缓冲区 读取 int32      更新时间:2023-10-16

给定一个包含 int(小端序)的字符缓冲区 c。如何将其视为int32_t?

我写了这段代码,但它感觉不像惯用的 cpp。

int32_t v;
char* p = (char*)&v;
for (int i=0; i < 4; i++) {
    *(p+i) = *(c+i);
}

二进制数据从char*缓冲区复制到任何其他数据类型的唯一可移植方法是使用 memcpy(或等效的字节复制 merhod,如 std::copy 或您自己的模仿此行为的 merhod)。

 memcpy(&my_number, my_buffer, sizeof(my_number));

当然,缓冲区应包含给定数据类型的正确位。如果它源自同一台计算机上的相同数据tyoe内存复制,那么字节序就不会发挥作用。否则,您必须按所需顺序(就地或在临时缓冲区中)重新排列字节,或者在整数本身中以与平台相关的方式交换字节(可能与 htonl 和 friends)。

没有神奇的惯用方法来处理字节序 — 字节序是一个 I/O 问题。要么使用 htonl()ntohl() 函数(在每个系统上都可用),要么只是自己解码它们(就像您正在做的那样)。我建议编写函数来做到这一点(让你的生活更轻松,可验证)。

如果您想

以便携和安全的方式解决问题,请使用memcpy,因为 n.m. 的答案解释。否则,这里有一个更危险的技术:

请注意,这是 UB。仅当您完全确定缓冲区包含正确数量的数据并且缓冲区和数据正确对齐时,才使用以下技术。

如果确定系统的字节序与存储在char*缓冲区中的数据之一匹配,则可以使用 reinterpret_cast

std::int32_t v = *reinterpret_cast<std::int32_t*>(p);

没有符合标准的方法可以执行上述转换。有关更多详细信息,请参阅此问题。

没有标准函数来发现系统的字节序。但是,给定这样一个仅在小端系统上返回 true 的函数bool is_little_endian(),您可能会执行以下操作:

std::uint32_t read_from_little_endian(char* buf)
{
    std::uint32_t u;
    if(is_little_endian())
        std::copy(buf, buf + sizeof(u), (char*)&u);
    else
        std::reverse_copy(buf, buf + sizeof(u), (char*)&u);
    return u;
}

重要的一点始终是将您的std::uint32_t*投射到char*,因为只有char*才能合法地为所有其他类型的别名