【问题标题】:Is this code endian-safe?此代码字节序安全吗?
【发布时间】:2015-11-12 17:49:35
【问题描述】:

完全可以肯定,我想知道以下 C++ 代码是否安全,尤其是字节序安全?我希望这个程序能够从任何计算机写入二进制文件,然后从任何其他计算机(可以具有另一个字节顺序)读取文件(即可移植)。

#include <iostream>
#include <fstream>

using namespace std;

#define BUFF_SIZE 64

template <typename type> void toBin(type value, char * buffer, size_t size);
template <typename type> type toDec(char * buffer, size_t size);

int main()
{
    long long x = 238920134300912;

    char * buffer = (char*)calloc(BUFF_SIZE, sizeof(char));

    // Write x
    toBin<long long>(x, buffer, BUFF_SIZE);

    ofstream outFile("test.bin", ios::out | ios::binary);

    outFile.write(buffer, BUFF_SIZE);

    outFile.close();

    // -------------------------------------------------------------------------

    // Read x (from another computer...)
    ifstream inFile("test.bin", ios::in | ios::binary);

    inFile.read(buffer, BUFF_SIZE);

    cout << toDec<long long>(buffer, BUFF_SIZE) << endl;

    inFile.close();


    // Free the buffer.
    free(buffer);

    return 0;
}



template <typename type> void toBin(type value, char * buffer, size_t size)
{
    if (sizeof(type) > size)
        throw new invalid_argument("Buffer too small");

    for (size_t i = 0; i < sizeof(type); i++)
        buffer[i] = (value >> i * 8) & 0xff;
}


template <typename type> type toDec(char * buffer, size_t size)
{
    if (sizeof(type) > size)
        throw new invalid_argument("Buffer too small");

    type value = 0;

    for (size_t i = 0; i < sizeof(type); i++)
        value += ((type)buffer[i] & 0xff) << (8 * i);

    return value;
}

【问题讨论】:

  • 你为什么不直接读/写二进制文件???
  • @Walter 因为那绝对是不是 endian可移植的。
  • 你意识到例如sizeof(long) 在不同的机器上是不同的,对吧?您只能将其用于固定大小的类型,例如 uint32_t。
  • 顺便说一下,从不抛出指针。
  • 不要在 C++ 代码中使用 *alloc/free(和 C 风格的强制转换)。不。使用 RAII 或堆栈分配的变量。

标签: c++ file portability endianness


【解决方案1】:

除了一件事,它对我来说看起来不错。我会将8 替换为CHAR_BIT,将0xff 替换为UCHAR_MAX

buffer[i] = (value >> (i * CHAR_BIT)) & UCHAR_MAX;

value += ((type)buffer[i] & UCHAR_MAX) << (CHAR_BIT * i);

【讨论】:

  • 相邻使用 CHAR_BIT 和 0xff 有什么意义? ;)
  • @KonradRudolph 在 C++ 中,char 被定义为 8 位 {需要引用}
  • 真正关心每字节超过 8 位的系统有什么意义?顺便说一句,转换为 char 更好:编译器将处理存储。
  • @n.m.嗯,我想我记得某处的标准有 sizeof(char) sizeof(int16_t) 或 char16_t 或类似的限制,这意味着它始终是 8 位。显然我错了。
  • @black,你说的是(type)buffer[i]吗?
【解决方案2】:

你应该看看htons() family of functions。它们是库函数,可将主机的字节序转换为“网络字节序”,即大字节序。这些函数保证是可移植的,并且可能比您自己的实现更快。

如果您想确保可移植性,您还应该在多个平台上测试代码,以确保它确实有效。在大型程序中,您很可能会忘记在某处转换字节顺序。该程序仍然可以在原始平台上运行,因此您需要在另一个平台上对其进行测试以检测错误。

【讨论】:

  • 谢谢,但我如何在其他架构上测试我的程序(使用其他字节序)?是否有一些工具或虚拟机可以做到这一点?
  • 这取决于您要将程序移植到哪个平台。在实践中没有完全的可移植性,只有特定平台的可移植性。如果您没有考虑特定的平台,则无论如何都不应该担心可移植的字节序。
【解决方案3】:

是的,你可以这样做,但速度很慢。

或者,只需使用数据(以可移植方式)写入一个标志,指示文件上数据的字节序(您的写入程序甚至可以使用布尔参数指示它应该写入的字节序,默认为当前硬件的值)。然后,读取代码可以检测字节序是否兼容,如果需要,将字节翻转到位。

在写入器和读取器具有相同字节序的可能情况下,这只会给普通 I/O 增加很小的开销。 AFAIK,这是可移植二进制格式通常实现的方式(例如 HDF5)。

【讨论】:

  • 感谢您的建议,这是真的,但在我的情况下,性能并不重要,它只适用于少数数字。
猜你喜欢
  • 2015-10-12
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 2010-12-18
相关资源
最近更新 更多