我希望能够将大字节序float
数组直接从未对齐的网络缓冲区复制到,std::vector<float>
并执行字节交换回主机顺序“就地”,而无需涉及中间过程std::vector<uint32_t>
。这样安全吗?我担心大字节序浮点数据可能会意外地解释为NaN并触发意外行为。这是一个有效的关注吗?
出于此问题的目的,假定接收数据的主机为低端字节序。
这是一些代码,展示了我正在尝试做的事情:
std::vector<float> source{1.0f, 2.0f, 3.0f, 4.0f};
std::size_t number_count = source.size();
// Simulate big-endian float values being received from network and stored
// in byte buffer. A temporary uint32_t vector is used to transform the
// source data to network byte order (big endian) before being copied
// to a byte buffer.
std::vector<uint32_t> temp(number_count, 0);
std::size_t byte_length = number_count * sizeof(float);
std::memcpy(temp.data(), source.data(), byte_length);
for (uint32_t& datum: temp)
datum = ::htonl(datum);
std::vector<uint8_t> buffer(byte_length, 0);
std::memcpy(buffer.data(), temp.data(), byte_length);
// buffer now contains the big endian float data, and is not aligned at word boundaries
// Copy the received network buffer data directly into the destination float vector
std::vector<float> numbers(number_count, 0.0f);
std::memcpy(numbers.data(), buffer.data(), byte_length); // IS THIS SAFE??
// Perform the byte swap back to host order (little endian) in place,
// to avoid needing to allocate an intermediate uint32_t vector.
auto ptr = reinterpret_cast<uint8_t*>(numbers.data());
for (size_t i=0; i<number_count; ++i)
{
// IS THIS SAFE??
uint32_t datum;
std::memcpy(&datum, ptr, sizeof(datum));
*datum = ::ntohl(*datum);
std::memcpy(ptr, &datum, sizeof(datum));
ptr += sizeof(datum);
}
assert(numbers == source);
注意两个“这很安全吗?” 上面的评论。
动机:我正在编写一个支持类型数组的CBOR序列化库。CBOR允许类型化数组以大端或小端的形式传输。
编辑:替换reinterpret_cast<uint32_t*>
字节序在endian交换循环中的非法类型memcpy
。
编辑后:
关于auto datum = reinterpret_cast<uint32_t*>(numbers.data());
:这在C ++中是不允许的,只能安全地对它进行类型双打uint8_t
(仅当CHAR_BIT == 8时,更确切地说,此类型双工异常仅适用于char
类型)
旧答案:以下是编辑之前的问题(带有的问题bit_cast
)。
只要提供,这是安全的 sizeof(float) == sizeof(uint32_t)
不必担心会发出NaN信号。通常会禁用这些例外,即使启用了例外,它们也只会在生成信号NaN时发生。移动指令不会产生异常。
data()
支持通过指针访问矢量元素(用于读取和写入)。vector
保证有连续的存储。
但是,为什么不在没有临时缓冲区的情况下仅在一个循环中完成所有操作?
仅具有浮点向量(输入或输出)和数据缓冲区(uint8_t向量)。为了仅在float输入向量上发送迭代,请对每个元素执行字节交换并将4个字节写入数据缓冲区。一次一个。这样就不需要任何中间缓冲区。它可能不会变慢。对于接收,请执行相反的操作。
采用std::bit_cast
浮法转换自/至std::array<uint8_t,4>
。这将是C ++ 20中的“正确”方式(您不能直接在bit_cast中使用C数组)。使用这种方法,您无需调用ntohl
,只需按正确的顺序将字节从缓冲区复制到缓冲区即可。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句