Is this code, barring byte order issues, sufficient to write floats in a cross-platform and cross-hardware way?
void ConvertFloatToBytes(float mcFloaty, char *buffer)
{
//Asserts that they are in IEC 559 (aka IEEE 754) format, which is the most common format.
static_assert(std::numeric_limits<float>::is_iec559(), "The code requires we use the IEEE 754 floating point format for binary serialization of floats and doubles.");
//Convert to bytes.
unsigned char *bytes = reinterpret_cast<unsigned char*>(&type);
//We're assuming 'buffer' has enough space.
std::memcpy(buffer, bytes, sizeof(float));
}
Also, when and how do I need to handle byte order?
If I have an array of bytes, do I need to swap every four bytes in that array, regardless of what I put in the array, and regardless of whether the code is running on 64 bit or 32 bit hardware?
So, if I write the string, "0123456789", and I'm on a LittleEndian machine, and I want it converted to Network Byte Order (which I want to use for game file formats, for cross-platform use), the resulting order should be: "3210765498"?
Or do I just need to worry about integers and floats that are larger than one byte?
So using my byte-ordering code:
//Swaps between Big and Little endian types. Returns the result.
#define ChangeEndian16(value) (((value & 0xFF00) >> 8) | \
((value & 0x00FF) << 8))
#define ChangeEndian32(value) (((value & 0xFF000000ul) >> 24) | \
((value & 0x00FF0000ul) >> 8) | \
((value & 0x0000FF00ul) << 8) | \
((value & 0x000000FFul) << 24))
#define ChangeEndian64(value) (((value & 0xFF00000000000000ull) >> 56) | \
((value & 0x00FF000000000000ull) >> 40) | \
((value & 0x0000FF0000000000ull) >> 24) | \
((value & 0x000000FF00000000ull) >> 8) | \
((value & 0x00000000FF000000ull) << 8) | \
((value & 0x0000000000FF0000ull) << 24) | \
((value & 0x000000000000FF00ull) << 40) | \
((value & 0x00000000000000FFull) << 56))
inline int16_t LocalToBigEndian(int16_t value) { return (BigEndianOrder? value:ChangeEndian16(value)); }
inline uint16_t LocalToBigEndian(uint16_t value) { return (BigEndianOrder? value:ChangeEndian16(value)); }
inline int32_t LocalToBigEndian(int32_t value) { return (BigEndianOrder? value:ChangeEndian32(value)); }
inline uint32_t LocalToBigEndian(uint32_t value) { return (BigEndianOrder? value:ChangeEndian32(value)); }
inline int64_t LocalToBigEndian(int64_t value) { return (BigEndianOrder? value:ChangeEndian64(value)); }
inline uint64_t LocalToBigEndian(uint64_t value) { return (BigEndianOrder? value:ChangeEndian64(value)); }
#define LocalToNetworkOrder(value) LocalToBigEndian(value)
#define NetworkOrderToLocal(value) BigEndianToLocal(value)
.
Am I guaranteed this code will work on all Little and Big Endian architectures where IEEE 754 is used?
void ConvertFloatToBytes(float myFloat, char *buffer)
{
//Asserts that they are in IEC 559 (aka IEEE 754) format, which is the most common format.
static_assert(std::numeric_limits<float>::is_iec559(), "The code requires we use the IEEE 754 floating point format for binary serialization of floats and doubles.");
//Convert to network byte order.
uint32_t networkOrdered = LocalToNetworkOrder(reinterpret_cast<uint32_t>(myFloat));
//Convert to bytes.
unsigned char *bytes = reinterpret_cast<unsigned char*>(&networkOrdered);
//We're assuming 'buffer' has enough space.
std::memcpy(buffer, bytes, sizeof(float));
}