我们都知道,如果左操作数是
&&
,逻辑false
运算符就会短路,因为我们知道,如果一个操作数是false
,那么结果也是false
。
为什么按位运算符
&
不也短路?如果左操作数是0
,那么我们知道结果也是0
。我在(C、Javascript、C#)中测试过的每种语言都会评估两个操作数,而不是在第一个操作数之后停止。
有什么理由说明让
&
运算符短路是一个坏主意吗?如果不是,为什么大多数语言不让它短路呢?这似乎是一个明显的优化。
我猜这是因为源语言中的按位
and
通常会相当直接地翻译为按位 and
指令以由处理器执行。反过来,它又被实现为硬件中一组适当数量的and
门。
在大多数情况下,我认为这并没有优化任何东西。评估第二个操作数通常比测试是否应该评估它的成本要低。
短路不是优化装置。它是一种控制流量的装置。如果你未能短路
p != NULL && *p != 0
,你不会得到稍微慢一点的程序,你会得到一个崩溃的程序。
这种短路对于按位运算符几乎没有意义,and比普通的非短路运算符更昂贵。
按位运算通常非常便宜,以至于检查会使操作时间延长两倍或更多,而短路逻辑运算符的收益可能非常大。
如果编译器必须对 & 的两个操作数进行检查,我猜在任何正常条件下它都会慢得多。
出于同样的原因,如果第一个操作数为 0,
*
不会短路——这将是一个晦涩的特殊情况,为其添加特殊的运行时测试将使所有乘法变慢。
当操作数不是常量时,短路比不短路的代价更高,所以除非程序员明确要求,否则你不想这样做。 因此,您确实希望对于它何时发生有清晰且简单的规则。
布尔短路对于程序员来说是一种方便,因为这是他们通常想要的。如果它不存在,某些表达式 - 例如
p != NULL && *p != 0
会更难键入(但仍然可能)。
另一方面,按位运算符假定编程级别较低,并且完全按照键入的内容执行操作。在这种情况下,更有可能在没有短路的情况下工作。
如果按位运算符也发生短路,那么在不需要这种行为时处理这种情况将会更加麻烦。 如果我有一个表达式
doA() & doB()
,其中两个调用 must 在所有情况下都执行,那么我突然必须将其拆分为几个完整的语句。更不用说发现这些不太可能出现的错误是多么困难。