据我所知,一元运算符优先于||
和&&
。在下面的代码中,我期望输出所有输出都等于1.是的,存在短路,但不应该在||
和&&
之前计算那些预增量?这些优先级如何在这里工作?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0, b = 0, c = 0;
a = b = c == 1;
c = ++a || ++b && ++c; // short-circuit here
printf("a=%d, b=%d, c=%d\n", a, b, c);
}
Output:
a=1 b=0 c=1
答案 0 :(得分:3)
运算符优先级与评估顺序没有任何关系。更高的优先级意味着首先将操作数分组到该运算符。
声明
c = ++a || ++b && ++c;
++
的操作数的分组/绑定将首先进行,然后分别进行&&
和||
的操作数的分组/绑定。为了表明这一点,我在表达式中添加了括号
++
具有更高的优先级,因此首先将操作数绑定到它
c = (++a) || (++b) && (++c);
&&
的优先级高于||
c = (++a) || ((++b) && (++c));
||
的优先级高于=
c = ((++a) || ((++b) && (++c)));
=
所有
(c = ((++a) || ((++b) && (++c))));
答案 1 :(得分:2)
||
短路且最低优先级运算符解释结果。由于++
的优先级高于&&
且&&
的优先级高于||
,因此++a || ++b && ++c
的表达式树为:
|| -- left: ++a
-- right: && --left: ++b
--right: ++c
因此,为了评估表达式,C首先考虑评估||
的规则,由C11标准中的6.5.14给出。具体做法是:
6.5.14.4:与按位|不同运算符,||运营商保证从左到右的评估;如果计算第二个操作数,则在第一个和第二个操作数的计算之间存在一个序列点。如果第一个操作数将不等于0,则不计算第二个操作数。
||
短路的事实意味着它首先评估其左操作数,并且只有在左边为零时才评估其右操作数。因此,要评估表达式++a || ++b && ++c
,C需要以下内容:
++a
(a
加1,表达式等于其递增值)。如果它不为零,则||
表达式等于1
,并且永远不会评估右侧。 ++b
和++c
。如果++b
为零,则永远不会评估++c
。如果两者都不为零,则表达式等于1
。由于++a
的计算结果为1,因此永远不会评估||
的右侧。这就是您a==1
,b==0
和c==1
。
语句c = ++a || ++b && ++c
还有一个问题,即语句可能会调用未定义的行为。如果++a
为false且++b
为true,则必须对++c
进行评估。但是,c = ...
和++c
之间没有序列点。由于表达式都修改c
而两者之间没有序列点,因此行为未定义。有关此内容的进一步说明,请参阅https://stackoverflow.com/a/3575375/1430833
答案 2 :(得分:1)
我认为您将operator precedence与order of evaluation混为一谈。这里概述了发生的事情。在评论中,我对=
的使用是身份的 - 就像数学等号一样。
#include <stdio.h>
#include <stdlib.h>
int main()
{
// all variables are assigned the value 0
int a = 0, b = 0, c = 0;
// a and b are equal to the evaluation of `c == 1`, which is false. a and b are 0
a = b = c == 1;
/*
&& has higher precedence than ||, so ++b and ++c are "grouped": ++a || (++b && ++c)
++a is evaluated, a = 0+1 = 1. 1 is true, short circuit the second grouping.
c = a = 1.
*/
c = ++a || ++b && ++c; // short-circuit here
// a = c = 1, b = 0
printf("a=%d, b=%d, c=%d\n", a, b, c);
}