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++ 而言,无论是在编译时还是运行时,都无法检测到这一点。
我想创建一个 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:
— [...]
— areinterpret_cast
.
— [...]
并且,来自 [dcl.constexpr]:
For a
constexpr
function orconstexpr
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++ 而言,无论是在编译时还是运行时,都无法检测到这一点。