Vin*_*REC 0 c++ gcc clang constexpr c++17
我正在使用 Godbolt 来查看带有 gcc 和 clang 的生成代码。
我试图实现djb2 hash。
gcc 总是试图最好地评估 constexpr 函数。
只有当变量是 constexpr 时,clang 才会评估 constexpr。
让我们看看这个例子:
constexpr int djb2(char const *str)
{
int hash = 5381;
int c = 0;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
int main()
{
int i = djb2("hello you :)");
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,gcc 正在评估一个编译时间 i。但是在运行时叮当响。
如果我将 constexpr 添加到i,clang 也在编译时进行评估。
您知道标准是否对此有所说明吗?
编辑:谢谢大家。所以,据我所知,没有 constexpr 编译器正在做想要的。使用 constexpr,编译器被迫评估常量。
您的程序有未定义的行为。
hash << 5对于 C++20 之前的有符号整数类型,移位将溢出。
特别是这意味着调用您的函数永远不会产生常量表达式,您可以通过添加constexpr到您的i. 然后,两个编译器都必须诊断未定义的行为并告诉您。
给出hash一个无符号类型,您的代码实际上将具有明确定义的行为,并且该表达式djb2("hello you :)"实际上是一个可以在编译时计算的常量表达式,假设您使用的是 C++14 或更高版本(循环在constexprC++11 中的函数。)。
这仍然不需要编译器在编译时实际进行评估,但是您可以通过添加constexpr到i.
“力”在这里是相对的。由于as-if 规则,并且因为在编译时和运行时的计算之间没有可观察到的区别,所以在技术上仍然不需要编译器只在编译时真正进行计算,但它需要编译器检查整个有效性的计算,与求值基本相同,所以编译器在运行时重复求值是不合理的。
同样,“可以在编译时评估”也是相对的。出于与上述相同的原因,编译器仍然可以选择在编译时进行计算,即使它不是常量表达式,只要行为上没有任何可观察到的差异。这纯粹是优化器质量的问题。在您的特定情况下,程序具有未定义的行为,因此编译器无论如何都可以选择做他们想做的事。