Reputation: 91
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) (i.e 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;
}
Upvotes: 0
Views: 224
Reputation: 206607
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);
Upvotes: 2
Reputation: 7656
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" i.e. 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.
Upvotes: 1
Reputation: 45434
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).
Upvotes: 0