为什么按位运算符不像逻辑“和\或”运算符那样智能
我只是注意到按位操作不像逻辑“和\或”操作那样“智能”,我想知道为什么?
这是一个例子:
// For the record private bool getTrue(){return true;} private bool getFalse(){return false;} // Since a is true it wont enter getFalse. bool a = getTrue() || getFalse(); // Since a is false it wont enter getTrue. bool b = getFalse() && getTrue(); // Since b is false it wont enter getTrue. b = b && getTrue();
但是,按位运算符“| =”和“&=”并不那么聪明:
bool a = getTrue(); a |= getFalse(); // a has no chance to get false but it still enters the function. a = getFalse(); a &= getTrue(); // a has no chance to get true but still performs this operation.
我想知道他们为什么不以相同的逻辑方式工作。
一个澄清:
在bool
求bool
时,运算符&=
和|=
不是按位运算符 – 它们是逻辑运算符,但它们相当于x = x & y
和x = x | y
x = x | y
,不像&&
和||
那样短路 做。
来自MSDN :
&运算符对积分操作数和bool操作数上的逻辑AND执行按位逻辑AND运算。
设计人员可以实现||=
和&&=
,但由于它们只适用于布尔类型,因此没有多少价值。
D斯坦利的回答是正确的; 当你应用于bool
时,你的错误在于思考&
“按位”。 当应用于bool
时,最好将&
和&&
视为逻辑AND的急切和懒惰版本。
现在这是一个你没有问过的问题,但实际上是更有趣的问题:
为什么首先有一个非短路版本的AND和OR for
bool
? 也就是说,为什么你会说exprX & exprY
而不是exprX && exprY
?
不好的理由是:表达式exprY
可能会产生副作用,无论exprX
的值如何,您都希望始终发生这种exprX
。 这是一个不好的理由,因为将表达式用于其副作用及其值是一个值得怀疑的做法。
好的理由是:它可以更快地计算&
不是&&
。
怎么可能? 当然,如果我们可以在某些时候避免计算右侧,那么我们总能平均节省时间,对吧?
错误的错误。 z = x && y
将生成为具有以下结构的代码:
if x goto CONSEQUENCE z = false goto DONE CONSEQUENCE: z = y DONE:
与简单地计算x & y
并将结果分配给z
相比,这是很多指令,大型代码需要更多时间来加载磁盘,更多时间进行jit编译,并在处理器缓存中占用更多空间。
而且,这些指令包含条件分支和非条件分支,大大增加了抖动必须处理的基本块的数量。 (“基本块”是一段具有明确开始和结束的代码,如果没有exception,基本块中的所有代码都会执行。)当基本块的数量时,抖动可能会选择避开某些优化必须分析得太大。
最糟糕的是,任何条件分支都为CPU提供了分支预测器做出错误选择的机会,这在某些情况下可能会产生严重的性能影响。
现在,这并不是说你永远不应该使用&&
作为bools; 目前还没有程序在市场上取得的巨大成功归功于这种纳米优化的使用。 我只是因为并不完全明显为什么在bool上应该有一个非短路的逻辑运算符。
主要区别在于您是否正在使用|
/ &
或||
/ &&
。 后者的短路(你称之为“智能”),而前者则没有(这是处理布尔类型时运算符之间的唯一区别)。 由于没有&&=
或||=
运算符,因此您只注意到&=
和|=
,正如符号所示,它不会短路。
我认为很可能是&=
和|=
存在但是&&=
和||=
不存在,因为前者在数字类型中使用,其中短路没有意义。