&&优先于||

据我所知,逻辑运算符&&优先级高于|| 。 在运行代码:

 #include <stdio.h> int main() { int i = 1, j =1, k = 1; printf("%d\n",++i || ++j && ++k); printf("%d %d %d",i,j,k); return 0; } 

正在给出的输出:

 1 2 1 1 

这只有在++i || ++j && ++k时才有可能 ++i || ++j && ++k是这样评估的:

 (++i) || (++j && ++k) 

但是,根据运营商的优先规则,它应该被评估为:

 (++i || ++j) && (++k) 

因此产出应该是:

 1 2 1 2 

这是怎么回事?

注:根据我的理解,我认为更高优先级的运算符评估如下( 如果它是左联合的 ):
评估它的左边的expression
2.然后评估其正确的expression(如果需要)
我错了吗?

你说:

这只有在++i || ++j && ++k时才有可能 ++i || ++j && ++k是这样评估的:

 (++i) || (++j && ++k) 

但是,根据运营商的优先规则,它应该被评估为:

 (++i || ++j) && (++k) 

第一个分组是正确的,因为&&的优先级高于||的优先级 。 然后整个expression式评估||的LHS ,增加i的副作用,评估为真。 这意味着||的RHS ( &&expression式)根本不被评估,因为不需要确定整个expression式的真实性。

所以,编译器是正确的; 你以某种方式误解了优先权。


为什么第一个分组是正确的? 根据第一个分组||&&具有更高的优先级。 我怎么了?

你看不懂优先顺序,或者你不了解优先顺序与评估顺序的相互作用。 第一个分组给了&&更高的优先级。

如果你有a + b * c ,其中*的优先级高于+ ,那么它被评估为a + (b * c) ,不是吗? 将+更改为||*&&和expression式是同构的和解释是相似的。

算术expression式和逻辑expression式的区别在于,逻辑expression式的操作数必须从左到右进行计算,但是算术expression式的操作数不要; 编译器可以在评估之前评估b * c (但在添加之前必须评估b * c )。 相比之下,在逻辑expression式( a || b && c )中,编译器必须在评估b && c之前评估b && c ,并且当a变为true时,它不能评估bc ,更不用说b && c

|| 运算符短路 – 如果其第一个操作数的计算结果为真(非零),则不计算其第二个操作数。

&&也是如此,如果第一个操作数是假的,它不使用它的第二个操作数。 这是一个可能的优化,因为任何布尔值OR true都是true,同样,任何布尔值AND false都是false。


好的,所以你把评估顺序搞混了。 这里什么都不是矛盾的:

 ++i || ++j && ++k 

被分组为

 (++i) || (++j && ++k) 

因为&&具有更高的优先级。 但是这个OR操作的LHS是真的,所以整个RHS和它的AND操作都被丢弃了,没有被评估。


在编辑中给你留意:是的,你错了:运算符优先级与评估顺序依然不一样。 这只是分组。

首先,如你自己所说的, &&具有更高的优先级,这意味着操作数分组应该是

  (++i) || (++j && ++k) 

为什么你说“根据运算符优先级”应该是(++i || ++j) && (++k)对我来说是不清楚的。 这只是与你自己说的相矛盾。

其次,运营商的优先级与评估的顺序完全没有关系。 运算符优先级决定了运算符和它们的操作数之间的分组 (即运算符优先级说哪个运算符属​​于哪个运算符)。

同时, 评价顺序是一个完全不同的故事。 它要么保持不明确,要么由完全不同的规则来定义。 在||情况下 和&&操作员的评估顺序的确定义是从左到右(尽可能强制提前完成)。

所以,运营商优先规则告诉你,分组应该是

  (++i) || ((++j) && (++k)) 

现在,评估顺序规则告诉你,首先我们评估++i ,然后(如果需要的话)评估++j ,然后(如果需要的话)评估++k ,然后评估&&最后评估||

由于您误解了优先级,我们试着用一个math例子来清除它。 乘法和除法的优先级高于加法和减法。 这意味着这个expression式:

 a + b * c - d / e 

可以这样写:

 a + (b * c) - (d / e) 

既然你正确地表示&&||有更高的优先级 ,这个expression式:

 i || j && k 

可以这样写:

 i || (j && k) 

你可以把它看作是“优先级最高的操作首先加括号”,如果有帮助的话。

(但优先次序与评估有所不同 – 如果i是真的,那么(j && k)永远不会被评估。)