据我所知,逻辑运算符&&
的优先级高于||
。在运行代码时:
#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)
因此输出应为:
1
2 1 2
这有什么问题?
注意:根据我的理解,我认为优先级较高的运算符评估如下(如果它是左关联):
1.评估其左表达
2.然后评估其正确表达(如果需要)
我错了吗?
答案 0 :(得分:12)
||
运算符short-circuits - 如果其第一个操作数的计算结果为true(非零),则不会计算其第二个操作数。
&&
也是如此,如果第一个操作数为false,则不使用第二个操作数。这是一种可能的优化,因为任何布尔值OR true都是真的,同样,任何布尔值AND false都是false。
好的,所以你的评价顺序令人困惑。这里没有什么是矛盾的:
++i || ++j && ++k
分组为
(++i) || (++j && ++k)
因为&&
具有更高的优先级。但是,OR运算的LHS是正确的,因此整个RHS 及其AND运算被丢弃,不进行评估。
编辑中的注释:是的,您错了:运算符优先级仍然与评估顺序不同。它只是分组。
答案 1 :(得分:9)
首先,正如您自己所说,&&
具有更高的优先级,这意味着操作数分组应该是
(++i) || (++j && ++k)
为什么你说“根据运算符优先级”它应该是(++i || ++j) && (++k)
我不清楚。这恰恰与你自己说的相矛盾。
其次,运算符优先级与评估顺序完全无关。运算符优先级指示运算符与其操作数之间的分组(即运算符优先级表示哪个操作数属于哪个运算符)。
与此同时,评估顺序是一个完全不同的故事。它要么保持未定义,要么由完全不同的规则集定义。对于||
和&&
运算符,评估顺序确实定义为从左到右(尽可能强制提前完成)。
因此,运算符优先级规则告诉您分组应该是
(++i) || ((++j) && (++k))
现在,评估顺序规则告诉您,首先我们评估++i
,然后(如有必要)我们评估++j
,然后(如有必要)我们评估++k
,然后我们评估&&
,最后评估||
。
答案 2 :(得分:8)
你说:
只有在
++i || ++j && ++k
被评估时才有可能:(++i) || (++j && ++k)
但是,根据运算符优先级规则,它应该被评估为:
(++i || ++j) && (++k)
第一个分组是正确的,因为&&
的优先级高于||
的优先级。然后,表达式作为一个整体评估||
的LHS,其副作用是递增i
,其评估结果为真。这意味着||
(&&
表达式)的RHS根本没有被评估,因为不需要确定整体表达式的真实性。
所以,编译器是正确的;你以某种方式误解了优先权。
为什么第一个分组正确?根据第一个分组
||
的优先级高于&&
。我出了什么问题?
您似乎不了解优先权,或者您不理解优先级与评估顺序的相互作用。第一个分组优先于&&
。
如果您有a + b * c
,其中*
的优先级高于+
,那么它会被评估为a + (b * c)
,不是吗?将+
更改为||
,将*
更改为&&
,并且表达式是同构的,并且解释类似。
算术表达式和逻辑表达式之间的最大区别在于逻辑表达式的操作数必须从左到右进行计算,但算术表达式的操作数不能;在评估b * c
之前,编译器可以评估a
(但必须在进行添加之前评估b * c
)。相比之下,在逻辑表达式(a || b && c
)中,编译器必须在评估a
之前评估b && c
,并且当a
结果为真时,必须不评估b
或c
,更不用说b && c
了。
答案 3 :(得分:3)
由于你误解了优先权,让我们试着用一个数学例子来解决它。乘法和除法具有比加法和减法更高的优先级。这意味着这个表达式:
a + b * c - d / e
可以这样写:
a + (b * c) - (d / e)
由于您正确地声明&&
的优先级高于||
,因此表达式为:
i || j && k
可以这样写:
i || (j && k)
您可以将其视为“具有最高优先级的操作首先获得括号”,如果这有帮助的话。
(但优先级与评估不同 - 如果i
为真,则永远不会评估(j && k)
。)