Question:
Hello everyone!
Now I have code like this:
// Source.hpp
/**
* @brief Method that checks the endian type on the system.
* @return DATA_LITTLE_ENDIAN(0x02) - if on the system little endian, otherwise - DATA_BIG_ENDIAN(0x01).
*/
static inline DATA_ENDIAN_TYPE CheckSystemEndian(void) noexcept
{
const union {
const uint16_t value;
const uint8_t data[sizeof(uint16_t)];
} endian { 0x0102 };
return static_cast<DATA_ENDIAN_TYPE>(endian.data[0]);
}
Class Foo
{
static const DATA_ENDIAN_TYPE system_endian;
}
// Source.cpp
inline const DATA_ENDIAN_TYPE BinaryDataEngine::system_endian = CheckSystemEndian();
What is required: I want to solve this problem at compile-time
, therefore I need to redo the CheckSystemEndian()
function to constexp
. However, in this task, union
really bothers me.
The error is as follows:
constexpr function never produces a constant expression. Read of member 'data' of union with active member 'value' is not allowed in a constant expression.
Please suggest a way to achieve the required functionality in compile-time
. Thank you.
Answer:
As far as I know, it is impossible to determine the endianness at the compilation stage in principle (by standard means). This requires a reinterpret_cast
, and it is not considered a constexpr
expression.
In C ++ 20, std::endian
will appear for this, and it will be possible to write like this:
#include <type_traits>
constexpr bool is_big_endian = std::endian::native == std::endian::big;
constexpr bool is_little_endian = std::endian::native == std::endian::little;
While waiting for C ++ 20, you can use non-standard compiler features. For example, GCC can do this:
constexpr bool is_big_endian = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;
constexpr bool is_little_endian = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
In addition, you have undefined behavior in your program, because C ++, unlike C, does not allow reading from an inactive union field. Proof.
Here's an example of how you can fix the code:
static inline DATA_ENDIAN_TYPE CheckSystemEndian(void) noexcept
{
const uint16_t value = 0x0102;
return static_cast<DATA_ENDIAN_TYPE>((uint8_t &)value);
}
In addition, it also takes up less space.