constexpt function with anonymous union in C++

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.

Scroll to Top