为什么算术表达式没有在C#中乘以0进行优化

时间:2013-01-31 16:32:40

标签: c# programming-languages expression compiler-optimization

为了评估乘法,你必须评估第一个术语,然后是第二个术语,最后将这两个值相乘。

假设每个乘以0的数字为0,如果第一项的评估返回0,我会期望在不评估第二项的情况下将整个乘法计算为0。

但是,如果您尝试此代码:

var x = 0 * ComplexOperation();

尽管我们知道x为0,但仍会调用函数ComplexOperation。

优化的行为也与布尔运算符'&&'一致仅当第一项被评估为真时才评估第二项。 ('&'运算符在任何情况下都会评估这两个术语)

我在C#中测试了这种行为,但我猜几乎所有语言都是一样的。

4 个答案:

答案 0 :(得分:15)

首先,对于浮点数,你的断言甚至都不是真的!请注意0 * inf不为0,0 * nan不为0.

但更一般地说,如果您正在讨论优化,那么我想编译器可以自由地评估ComplexOperation是否可以证明没有副作用。

但是,我认为你真的在谈论短路语义(即语言功能,而不是编译器功能)。如果是这样,那么真正的理由是C#正在复制早期语言(最初为C)的语义以保持一致性。

答案 1 :(得分:6)

C#不起作用,因此功能可能有副作用。例如,您可以从ComlpexOperation内部打印某些内容或更改全局静态变量。因此,它是否被调用是由*合同定义的。

您发现自己是与&&&签订不同合同的示例。

答案 2 :(得分:3)

该语言定义哪些运算符具有短路语义,哪些运算符不具有短路语义。你的ComplexOperation函数可能有副作用,这些副作用可能是故意的,并且编译器不能自由地假设它们不应该只是因为函数的结果没有被使用而发生。

答案 3 :(得分:2)

我还要补充一下,这将是混淆语言设计。对于......的影响,会有大量的SO问题。

//why is foo only called 9 times?????????
for(int i = 0; i < 10; i++) {
    print((i-5)*foo());
}

为什么允许短路布线而不是短路0*?好吧,首先我要说混合短路布尔与副作用是代码中常见的错误来源 - 如果在维护人员中很好地理解它是一个明显的模式,那么它可能没关系,但对我来说很难想象程序员在0时整数习惯于整数洞。