为什么当你将函数的返回值乘以零时它不会短路?

Why doesn't it short-circuit when you multiply the return value of a function by zero?

本文关键字:零时 短路 当你 函数 返回值 为什么      更新时间:2023-10-16

考虑如下函数:

unsigned int fact(unsigned int i) {
if (i <= 1) { return 1; }
return i * fact(i-1);
}

如果我要实例化一个新的变量unsigned int f这样f = 0 * fact(5),为什么它不"短路"?

unsigned int fact(unsigned int i) {
std::cout << "a";
if (i <= 1) { return 1; }
return i * fact(i-1);
}
int main() {
unsigned int f = 0 * fact(5);
}

此处的输出为aaaaa.如果f只能为零,那么假设它知道返回类型,它为什么要调用该函数?它不是从左到右评估,看到0 * (unsigned int)并知道右值将被0吗?

短路评估对于&&(逻辑(、||(逻辑(和?(三元运算符(是强制性的。对于其余运算符,这是一个(可选(优化。

表达式0 * fact(5)fact(5)的计算通常不能仅仅因为您知道整个表达式的结果是0而优化,因为对fact()的调用可能会引入副作用(例如,修改某些全局变量(,因此必须调用它。

正如这篇评论中所说,一个好的编译器如果能证明没有副作用,就会优化对fact(5)的调用。

它是否不从左到右计算,请参阅 0 *(无符号整数(并知道右值将为 0?

它可以,如果标准告诉它,它会的。

但事实并非如此。

短路根本不是乘法的事情。他们本可以把它变成一件事,但可以说是令人困惑的。

我们都习惯于f() || g()可能会跳过对g()的调用,但你真的希望0 * g()做同样的事情吗?特别是因为0只是数十亿个可能的整数中的一个?这将是一个奇怪的特定功能。(相比之下,true是仅有的两个布尔值中的一个。

这与副作用无关,因为如果f()返回truef() || g()会跳过g()的副作用。事情就是这样。

在实践中,如果编译器知道g()没有副作用(因此程序的行为不会改变(,它可以避免0 * g()g()调用,但这不是短路;这就是"优化"。