Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Endianness in constexpr

I want to create a constexpr function that returns the endianness of the system, like so:

constexpr bool IsBigEndian()
{
    constexpr int32_t one = 1;
    return (reinterpret_cast<const int8_t&>(one) == 0);
}

Now, since the function will get executed at compile time rather than on the actual target machine, what guarantee does the C++ spec give to make sure that the correct result is returned?

like image 709
Rick de Water Avatar asked Jun 16 '16 18:06

Rick de Water


People also ask

What is the benefit of constexpr?

A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations. And when a value is computed at compile time instead of run time, it helps your program run faster and use less memory.

Is constexpr faster?

Try it on your code baseNot only will your code be faster and smaller, it'll be safer. Code marked constexpr can't bitrot as easily.

Does constexpr compile time?

constexpr functions will be evaluated at compile time when all its arguments are constant expressions and the result is used in a constant expression as well.

Is constexpr function static?

The constexpr function is executed in a context that is evaluated at compile time. This can be a static_assert expression, such as with the type-traits library or the initialization of a C-array.


2 Answers

None. In fact, the program is ill-formed. From [expr.const]:

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:
— [...]
— a reinterpret_cast.
— [...]

And, from [dcl.constexpr]:

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.20), or, for a constructor, a constant initializer for some object (3.6.2), the program is ill-formed; no diagnostic required.


The way to do this is just to hope that your compiler is nice enough to provide macros for the endianness of your machine. For instance, on gcc, I could use __BYTE_ORDER__:

constexpr bool IsBigEndian() {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    return false;
#else
    return true;
#endif
}
like image 138
Barry Avatar answered Sep 29 '22 21:09

Barry


As stated by Barry, your code is not legal C++. However, even if you took away the constexpr part, it would still not be legal C++. Your code violates strict aliasing rules and therefore represents undefined behavior.

Indeed, there is no way in C++ to detect the endian-ness of an object without invoking undefined behavior. Casting it to a char* doesn't work, because the standard doesn't require big or little endian order. So while you could read the data through a byte, you would not be able to legally infer anything from that value.

And type punning through a union fails because you're not allowed to type pun through a union in C++ at all. And even if you did... again, C++ does not restrict implementations to big or little endian order.

So as far as C++ as a standard is concerned, there is no way to detect this, whether at compile-time or runtime.

like image 25
Nicol Bolas Avatar answered Sep 29 '22 19:09

Nicol Bolas