在 C++23 中,该[[assume(expression)]]属性使得如果表达式为false,则行为未定义。例如:
int div(int x, int y) {
[[assume(y == 1)]];
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
y这会编译成与始终相同的代码1。
div(int, int):
mov eax, edi
ret
Run Code Online (Sandbox Code Playgroud)
但是,如果存在另一级别的未定义行为,会发生什么情况?
int div(int x, int y) {
[[assume(x / 0 == 1)]];
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
现在假设里面有UB,但是假设没有被评估。这是什么意思?这只是无稽之谈还是编译器可以用这个假设做任何事情?
最近,我发现void __builtin_assume(bool)了 clang,它可以向编译器提供有关程序状态的附加信息。这可以产生巨大的差异,例如:
#include <cstddef>
// compiles to about 80 instructions at -O3
unsigned sum(unsigned data[], size_t count) {
unsigned sum = 0;
for (size_t i = 0; i < count; ++i) {
sum += data[i];
}
return sum;
}
// compiles to about 10 instructions at -O3
unsigned sum_small(unsigned data[], size_t count) {
__builtin_assume(count <= 4);
unsigned sum = 0;
for (size_t i = 0; i < count; ++i) {
sum += data[i];
}
return …Run Code Online (Sandbox Code Playgroud) cppreference页面[[assume]]说:
Run Code Online (Sandbox Code Playgroud)[[assume( expression )]][...] 表达式没有被求值(但它仍然可能被求值)。
这个措辞让我很困惑。这里 cppreference 错了吗?如果不评估,为什么可能会评估?它不是像 中的表达式一样未计算的操作数吗sizeof?如果不可以,后果是什么?
在 C++23 中,该[[assume(conditonal-expression)]]属性使得如果条件表达式的计算结果不为true,则行为未定义。例如:
int div(int x, int y) {
[[assume(y == 1)]];
return x / y;
}
Run Code Online (Sandbox Code Playgroud)
y这会编译成与始终相同的代码1。
div(int, int):
mov eax, edi
ret
Run Code Online (Sandbox Code Playgroud)
正如评论者所指出的,这不是必需的优化;这正是 GCC 碰巧处理的信息,除了y == 1UB 之外什么都没有。
编译器完全忽略所有假设是有效的。
编译器需要诊断常量表达式1)中所有未定义的行为,但这合理吗?例如:
constexpr bool extremely_complicated(int x) {
bool result;
// 10,000 lines of math ...
return result;
}
constexpr int div(int x, int y) {
// This should result in a compiler error when the compiler …Run Code Online (Sandbox Code Playgroud)