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.
I have this code that allow me to convert from HOST_ENDIAN_ORDER (whatever it is) to LITTLE_ENDIAN_ORDER or BIG_ENDIAN_ORDER. I use a template, so if I try to convert from HOST_ENDIAN_ORDER to LITTLE_ENDIAN_ORDER and they happen to be the same for the machine for wich I compile, no code will be generated.
Here is the code with some comments:
There is an assembly instruction called BSWAP that will do the swap for you, extremely fast. You can read about it here.
Visual Studio, or more precisely the Visual C++ runtime library, has platform intrinsics for this, called
_byteswap_ushort(), _byteswap_ulong(), and _byteswap_int64()
. Similar should exist for other platforms, but I'm not aware of what they would be called.Wow, I couldn't believe some of the answers I've read here. There's actually an instruction in assembly which does this faster than anything else. bswap. You could simply write a function like this...
It is MUCH faster than the intrinsics that have been suggested. I've disassembled them and looked. The above function has no prologue/epilogue so virtually has no overhead at all.
Doing 16 bit is just as easy, with the exception that you'd use xchg al, ah. bswap only works on 32-bit registers.
64-bit is a little more tricky, but not overly so. Much better than all of the above examples with loops and templates etc.
There are some caveats here... Firstly bswap is only available on 80x486 CPU's and above. Is anyone planning on running it on a 386?!? If so, you can still replace bswap with...
Also inline assembly is only available in x86 code in Visual Studio. A naked function cannot be lined and also isn't available in x64 builds. I that instance, you're going to have to use the compiler intrinsics.
Most platforms have a system header file that provides efficient byteswap functions. On Linux it is in
<endian.h>
. You can wrap it nicely in C++:Output:
The same way you do in C:
You could also declare a vector of unsigned chars, memcpy the input value into it, reverse the bytes into another vector and memcpy the bytes out, but that'll take orders of magnitude longer than bit-twiddling, especially with 64-bit values.
Note that, at least for Windows, htonl() is much slower than their intrinsic counterpart _byteswap_ulong(). The former is a DLL library call into ws2_32.dll, the latter is one BSWAP assembly instruction. Therefore, if you are writing some platform-dependent code, prefer using the intrinsics for speed:
This may be especially important for .PNG image processing where all integers are saved in Big Endian with explanation "One can use htonl()..." {to slow down typical Windows programs, if you are not prepared}.