I have this little gem here (idea shamlessly stolen from the C-FAQ):
/* A lot of checks omitted to get rid of the architectures with a "weird" endianness */
/*...*/
#define MP_ENDIANESS ( (0x41424344ul == *(uint32_t*)"ABCD") ? MP_BIG_ENDIAN : MP_LITTLE_ENDIAN )
Is it compliant (that is not an undefined behaviour) to the new current standard (C-18 at the time this question has been asked) and if yes, which of the older ones support it, too?
Is it also standard compliant C++? (Yes, I know about std::endian
)
It has several issues:
uint32_t
isn't guaranteed to exist"ABCD"
, an array decaying to a char*
(C) /char const*
(C++), is not guaranteed to be suitably aligned for uint32_t*
. If it isn't, the cast is UB*(uint32_t*)"ABCD"
) is a strict aliasing violation (UB)You might want to simply do something like this instead:
#if !__cplusplus
#define LITTLE_ENDIAN_EH() (*(char*)&(int){1});
#else
//C++ doesn't have compound literals
static int const LITTLE_ENDIAN_EH_ = 1;
#define LITTLE_ENDIAN_EH() (*(char*)&LITTLE_ENDIAN_EH_)
#endif
(Works because char
will exist, can alias anything, and has minimal alignment requirements.)
All the macros, including your attempts, have the disadvantage of being unsuitable for preprocessor conditionals (#if ...
) or in contexts where an integer constant expression is required (case
labels, array sizes, bitfield sizes), but when used elsewhere, modern compilers will generally treat the result as a compile time constant as far as optimized assembly output is concerned.
This is not defined behavior in C++. *(uint32_t*)"ABCD"
treats the memory of "ABCD"
as if it were an uint32_t
, but since it isn't really, this is a strict aliasing violation and undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With