constexpr 中的字节顺序

Endianness in constexpr

我想创建一个 returns 系统字节顺序的 constexpr 函数,如下所示:

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

现在,由于函数将在编译时而不是在实际的目标机器上执行,C++ 规范提供什么保证来确保返回正确的结果?

None。事实上,这个程序是病式的。来自 [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.
— [...]

并且,来自 [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.


这样做的方法只是希望您的编译器足够好,可以为您的机器的字节顺序提供宏。例如,在 gcc 上,我可以使用 __BYTE_ORDER__:

constexpr bool IsBigEndian() {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    return false;
#else
    return true;
#endif
}

正如 Barry 所说,您的代码不是合法的 C++。但是,即使您去掉了 constexpr 部分,它 仍然 不是合法的 C++。您的代码违反了严格的别名规则,因此代表了未定义的行为。

确实,在 C++ 中没有办法在不调用未定义行为的情况下检测对象的字节顺序。将其强制转换为 char* 是行不通的,因为该标准不要求大端或小端顺序。因此,虽然您可以通过一个字节读取数据,但您无法从该值合法地推断出任何内容。

并且通过 union 输入双关失败,因为在 C++ 中根本不允许通过 union 输入双关。即使您这样做了……再一次,C++ 不会将实现限制为大端或小端顺序。

因此,就作为标准的 C++ 而言,无论是在编译时还是运行时,都无法检测到这一点。