I'm writing and reading binary data (std::ios::binary
) in C++ using std::fstream
- this includes integer and floating point values. While my code works on my own architecture, I wan't to make sure, that it's portable and i.e. binary files written on my machine shall still be read properly of an machine with different endianness. So my idea was that I will add in the binary file at first byte a value which will indicate the endianness of the file.
As there is no guarantee, that endianness of integer and floating points are the same, I need to get the information for both datatypes separately. While getting the endianess for integer was rather simple with pointer arithmetic, I'm lost how to get the endianess for float at runtime. Any idea?
My code looks like:
#include <cstdint>
#define INT_LITTLE_ENDIAN 0x01u
#define INT_BIG_ENDIAN 0x02u
#define FLOAT_LITTLE_ENDIAN 0x04u
#define FLOAT_BIG_ENDIAN 0x08u
uint8_t getEndianess(){
uint8_t endianess = 0x00;
uint16_t integerNumber = 0x1;
uint8_t *numPtr = (uint8_t*)&integerNumber;
if (numPtr[0] == 1) {
endianess |= INT_LITTLE_ENDIAN;
}else {
endianess |= INT_BIG_ENDIAN;
}
/* TODO: check endianess for float */
return endianess;
}
A check for float
endian is also a check for the encoding.
If the encoding is not float32
, detect that.
Instead of checking with a byte pattern like 0xBF800000 (-1.0f) with multiple zero bytes, consider using a pattern where the expected byte pattern is different for every byte. Also check every byte.
const float f = -0x1.ca8642p-113f; // 0x87654321, IEEE-754 binary32
if (sizeof(float) != 4) {
printf("float is not 4 bytes\n");
} else if (memcmp(&f, (uint8_t[4]){0x87, 0x65, 0x43, 0x21}, sizeof f) == 0) {
printf("Big\n");
} else if (memcmp(&f, (uint8_t[4]){0x21, 0x43, 0x65, 0x87}, sizeof f) == 0) {
printf("Little\n");
} else {
printf("Unknown\n"); // TBD endian or float encoding
}