提问人:Alex 提问时间:11/9/2023 最后编辑:Alex 更新时间:11/11/2023 访问量:66
在写入 Buffer 类时,是否需要考虑主机的字节序?
Do I need to account for host machine's endianness when writing to my Buffer class?
问:
我正在编写一个 Buffer 类,它只是在 C++ 中保存字节。它具有各种类型的常用读写方法;16、32 和 64 位整数、浮点数和双精度数。我主要将其用于内存中加载/处理和文件 I/O,以后可能还会使用一些网络。
该类不完全依赖于主机的字节序,而是具有内置的字节序开关,因此所有读取和写入方法都将按所需顺序将给定值的基础字节读取/写入其目标。
我的问题是,我是否应该考虑运行此程序的机器的字节序,同时还要观察缓冲区的选定字节序模式?
例:
void Buffer::WriteInt32(int _int)
{
bvec bytes;
for (int i = 0; i < SIZE_INT32; i++)
{
bytes.push_back
(
_int >> (m_Endianness == Endian::BIG ? ((SIZE_INT32 * 8) - ((i + 1) * 8)) : i * 8)
);
}
m_Bytes.insert(std::end(m_Bytes), std::begin(bytes), std::end(bytes));
m_Length += SIZE_INT32;
}
此示例方法有效,并根据用户的偏好以大端或小端顺序写入。但是,我偷偷怀疑我应该检查运行此代码的机器的字节序,如果系统的字节序和缓冲区的设置匹配,我应该检查运行此代码的机器的字节序,并直接写入字节而不进行更改......这是我应该做的吗?由于我实际上没有选择在另一台机器上进行测试,因此我对场景可能如何发展感到困惑。
同样,对于阅读:
bool Buffer::ReadInt32(int& dest, bool useOffset, size_t offset)
{
int val = 0;
size_t index = useOffset ? offset : m_ReadOffset;
if (ReadableRemaining(index) < SIZE_INT32)
return false;
for (auto i = 0; i < SIZE_INT32; i++)
{
val <<= 8;
val |= m_Bytes[m_Endianness == Endian::BIG ? F_VAL(index, i) : R_VAL(index, i, SIZE_INT32)];
}
dest = val;
m_LastReadSize = SIZE_INT32;
if (!useOffset)
AdvanceReadOffset();
return true;
}
该代码将从 4 个字节检索到的值存储到给定的整数目标中;字节的观察顺序基于缓冲区的字节序设置。同样,一切正常,但是运行此代码的机器可以反转 val 的输出吗?我是否需要在此处添加代码以根据主机进行交换?
答:
0赞
Alex
11/11/2023
#1
经过一段时间的思考,我回答了自己的问题。我只是有一种困惑的阴霾,使我当时无法看清事物:)
鉴于:
- 大端和小端计算机将其值存储在内存中 根据其指定的布局;
- 我的缓冲区类只按照给定的顺序存储原始字节,以便以后在内存中和其他地方使用;
- 该类的用户选择写入的每个值的字节序 单独到缓冲区/从缓冲区读取,而不管机器的字节序如何;
显然,在确定每个操作的给定字节范围是否需要顺序反转之前,我需要观察机器的字节序。如果机器顺序与所需的操作顺序匹配,则不进行反转;否则,它是。
我还考虑了您的一些建议:
- 切换到使用 std::int32_t、int64_t 等以避免意外。
- 我已经在读取和写入过程中使用我自己的硬编码 2/4/8 字节大小检查了各种类型的大小,因此切换到固定宽度类型更有意义。
- 该项目现在检查实现是否存在 IEEE-754 浮点一致性,如果没有它,将无法编译。这是我很高兴遵守的规则。至于再现值的准确性,不同的代码将以最合适的方式处理;需要确定性的东西很可能不会依赖于基本的浮点数 -> 字节 ->不同的机器 -> 浮点数转换。
- 特定于项目的文件格式已经设计为全面采用小端序,但也感谢您的建议。
评论
sizeof(int)
int
std::int32_t
std::uint32_t
)