5 ms·
FWIW there is a <sys/endian.h> on various BSDs that contains "beXXtoh", "leXXtoh", "htobeXX", "htoleXX" where XX is a number of bits (16, 32, 64). That header
by st_goliath 5y ago
FWIW there is a <sys/endian.h> on various BSDs that contains "beXXtoh", "leXXtoh", "htobeXX", "htoleXX" where XX is a number of bits (16, 32, 64).
That header is also available on Linux, but glibc (and compatible libraries) named it <endian.h> instead.
See: man 3 endian (https://linux.die.net/man/3/endian https://linux.die.net/man/3/endian)
Of course it gets a bit hairier if the code is also supposed to run on other systems.
MacOS has OSSwapHostToLittleIntXX, OSSwapLittleToHostIntXX, OSSwapHostToBigIntXX and OSSwapBigToHostIntXX in <libkern/OSByteOrder.h>.
I'm not sure if Windows has something similar, or if it even supports running on big endian machines (if you know, please tell).
My solution for achieving some portability currently entails cobbling together a "compat.h" header that defines macros for the MacOS functions and including the right headers. Something like this:
https://github.com/AgentD/squashfs-tools-ng/blob/master/include/compat.h#L64 https://github.com/AgentD/squashfs-tools-ng/blob/master/incl...
This is usually my go-to-solution for working with low level on-disk or on-the-wire binary data structures that demand a specific endianness. In C I use "load/store" style functions that memcpy the data from a buffer into a struct instance and do the endian swapping (or reverse for the store). The copying is also necessary because the struct in the buffer may not have proper alignment.
Technically, the giant macro of doom in the article takes care of all of this as well. But unlike the article, I would very much not recommend hacking up your own stuff if there are systems libraries readily available that take care of doing the same thing in an efficient manner.
In C++ code, all of this can of course be neatly stowed away in a special class with overloaded operators that transparently takes care of everything and "decays" into a single integer and exactly the above code after compilation, but is IMO somewhat cleaner to read and adds much needed type safety.
- tjoff 5y agoAt least historically windows have had big-endian versions as both SPARC and Itanium use big endian.
- electroly 5y agoItanium can be configured to run in either endianness (it's "bi-endian"). Windows on Itanium always ran in little-endian mode and did not support big-endian mode. The same was true of PowerPC. Windows never ran in big-endian mode on any architecture.
- anticristi 5y agoIndeed, I don't get the article. It's like writing "C is hard because here is how hard it is to implement memcpy using SIMD correctly." Please don't do that. Use battle-tested low-level routines. Unless your USP is "our software swaps bytes faster than the competition", you should not spend brain power on that.
- deleted 5y ago[deleted]
- nwallin 5y agoWindows/MSVC has _byteswap_ushort(), _byteswap_ulong(), _byteswap_uint64(). (note that unsigned long is 32 bits on Windows) It's ugly but it works. Boost provides boost::endian which allows converting between native and big or little, which just does the right thing on all architectures and compilers and compiles down to a no-op or bswap instruction instruction. It's much better than writing (and testing!) your own giant pile macros and ifdefs to detect the compiler/architecture/OS, include the correct includes, and perform the correct conversions in the correct places.