Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualServant of the Lord

Posted 22 July 2013 - 05:15 PM

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

#3Servant of the Lord

Posted 22 July 2013 - 05:15 PM

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

#2Servant of the Lord

Posted 22 July 2013 - 05:15 PM

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

#1Servant of the Lord

Posted 22 July 2013 - 05:14 PM

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

PARTNERS