简体   繁体   中英

Is this code endian-safe?

To be totally sure, I would like to know if the following C++ code is safe and especially endian safe? I want this program to be able to write from any computer in a binary file and then read the file from any other computer (that can have another endianness) (ie to be portable).

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

It looks good to me except one thing. I would replace 8 by CHAR_BIT and 0xff by UCHAR_MAX .

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

and

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

You should take a look at the htons() family of functions . They are library functions which convert between the host's endianness to "network byte-order" ie big-endianness. These functions are guaranteed to be portable and likely to be faster than your own implementation.

If you want to ensure portability, you should also test the code on several platforms, to make sure that it actually works. In a large program, you are very likely to forget to convert the endianness somewhere. The program would still work on the original platform, so you need to test it on another to detect the bug.

Yes, you can do that, but it's slow.

Alternatively, simply write with the data (in a portable way) a flag indicating endianness of the data on file (your write program may even take a boolean argument indicating which endianness it should write, defaulting to the value of the current hardware). Then, the reading code can detect whether the endianness is compliant and, if needed, flip the bytes in place.

In the likely case that writer and reader have the same endianness, this adds only a tiny overhead to an ordinary I/O. AFAIK, this is the way portable binary formats are usually implemented (such as HDF5).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM