这个代码端安全吗

Is this code endian-safe?

本文关键字:安全 代码      更新时间:2023-10-16

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

#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;
}

除了一件事,它对我来说很好。我将用CHAR_BIT代替8,用UCHAR_MAX代替0xff

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

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

您应该了解htons()函数族。它们是库函数,可以在主机的端序和"网络字节顺序"(即大端序)之间转换。这些函数保证是可移植的,并且可能比您自己的实现更快。

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

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

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

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