How do I convert between big-endian and little-endian values in C++?
EDIT: For clarity, I have to translate binary data (double-precision floating point values and 32-bit and 64-bit integers) from one CPU architecture to another. This doesn't involve networking, so ntoh() and similar functions won't work here.
EDIT #2: The answer I accepted applies directly to compilers I'm targetting (which is why I chose it). However, there are other very good, more portable answers here.
If you take the common pattern for reversing the order of bits in a word, and cull the part that reverses bits within each byte, then you're left with something which only reverses the bytes within a word. For 64-bits:
The compiler should clean out the superfluous bit-masking operations (I left them in to highlight the pattern), but if it doesn't you can rewrite the first line this way:
That should normally simplify down to a single rotate instruction on most architectures (ignoring that the whole operation is probably one instruction).
On a RISC processor the large, complicated constants may cause the compiler difficulties. You can trivially calculate each of the constants from the previous one, though. Like so:
If you like, you can write that as a loop. It won't be efficient, but just for fun:
And for completeness, here's the simplified 32-bit version of the first form:
From The Byte Order Fallacy by Rob Pyke:
TL;DR: don't worry about your platform native order, all that counts is the byte order of the stream your are reading from, and you better hope it's well defined.
Note: it was remarked in the comment that absent explicit type conversion, it was important that
data
be an array ofunsigned char
oruint8_t
. Usingsigned char
orchar
(if signed) will result indata[x]
being promoted to an integer anddata[x] << 24
potentially shifting a 1 into the sign bit which is UB.Simply put:
usage:
swap_endian<uint32_t>(42)
.The procedure for going from big-endian to little-endian is the same as going from little-endian to big-endian.
Here's some example code:
If a big-endian 32-bit unsigned integer looks like 0xAABBCCDD which is equal to 2864434397, then that same 32-bit unsigned integer looks like 0xDDCCBBAA on a little-endian processor which is also equal to 2864434397.
If a big-endian 16-bit unsigned short looks like 0xAABB which is equal to 43707, then that same 16-bit unsigned short looks like 0xBBAA on a little-endian processor which is also equal to 43707.
Here are a couple of handy #define functions to swap bytes from little-endian to big-endian and vice-versa -->
Here's how to read a double stored in IEEE 754 64 bit format, even if your host computer uses a different system.
For the rest of the suite of functions, including the write and the integer routines see my github project
https://github.com/MalcolmMcLean/ieee754