写入 Buffer 类时是否需要考虑主机的字节序?

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

我正在编写一个 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 的输出吗?我需要在这里添加代码来根据主机交换内容吗?

c++ memory byte buffer endianness
1个回答
0
投票

经过一段时间的思考,我已经回答了我自己的问题。我当时只是有一种迷茫的感觉,无法看清事情:)

鉴于:

  1. 大端和小端机器将它们的值存储在内存中 根据他们指定的布局;
  2. 我的缓冲区类只按照给定的顺序存储原始字节,以供以后在内存中和其他地方使用;
  3. 该类的用户选择写入的每个值的字节序 单独到缓冲区/从缓冲区读取,无论机器的字节顺序如何;

在确定每个操作的给定字节范围是否需要反转顺序之前,我显然需要观察机器的字节顺序。如果机器指令与期望的操作指令相符,则不进行反转;否则,就是这样。

我也考虑了您的一些建议:

  • 改用 std::int32_tint64_t 等以避免意外。
  • 我已经使用自己的硬编码 2/4/8 字节大小在读取和写入期间检查了各种类型的大小,因此切换到固定宽度类型更有意义。
  • 该项目现在检查实现是否存在 IEEE-754 浮点一致性,如果没有它,将无法编译。这是我很乐意遵守的规则。至于再现值的准确性,不同的代码会以最合适的方式处理;需要确定性的东西很可能不会依赖于基本的浮点 -> 字节 -> 不同的机器 -> 浮点转换。
  • 项目特定的文件格式已经被设计为全面的小端,但也感谢您的建议。
© www.soinside.com 2019 - 2024. All rights reserved.