关于运算符优先级的示例
An example about operator precedences
据我所知,一元运算符优先于 ||
和 &&
。在下面的代码中,我期望所有输出都等于 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
我认为您感到困惑 operator precedence with 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);
}
运算符优先级与求值顺序没有任何关系。更高的优先级意味着首先完成对该运算符的操作数分组。
在声明中
c = ++a || ++b && ++c;
先完成++
操作数的grouping/binding,然后分别完成&&
和||
的操作数。为了表明这一点,我在表达式
中添加了括号
++
具有更高的优先级,因此首先将操作数绑定到它
c = (++a) || (++b) && (++c);
&&
的优先级高于 ||
c = (++a) || ((++b) && (++c));
||
的优先级高于 =
c = ((++a) || ((++b) && (++c)));
=
的优先级最低
(c = ((++a) || ((++b) && (++c))));
||
短路和最低优先级运算符这一事实解释了结果。因为 ++
的优先级高于 &&
而 &&
的优先级高于 ||
,所以 ++a || ++b && ++c
的表达式树是:
|| -- left: ++a
-- right: && --left: ++b
--right: ++c
因此,为了计算表达式,C 首先考虑计算 ||
的规则,由 C11 标准中的 6.5.14 给出。具体来说:
6.5.14.4: Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares unequal to 0, the second operand is not evaluated.
||
短路的事实意味着它首先评估其左操作数,并且仅在左操作数为零时才评估其右操作数。因此,要计算表达式 ++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
为假且 ++b
为真,则必须评估 ++c
。但是,c = ...
和++c
之间没有序列点。由于表达式都修改 c
且中间没有序列点,因此行为未定义。有关此内容的进一步说明,请参阅
据我所知,一元运算符优先于 ||
和 &&
。在下面的代码中,我期望所有输出都等于 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
我认为您感到困惑 operator precedence with 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);
}
运算符优先级与求值顺序没有任何关系。更高的优先级意味着首先完成对该运算符的操作数分组。
在声明中
c = ++a || ++b && ++c;
先完成++
操作数的grouping/binding,然后分别完成&&
和||
的操作数。为了表明这一点,我在表达式
++
具有更高的优先级,因此首先将操作数绑定到它c = (++a) || (++b) && (++c);
&&
的优先级高于||
c = (++a) || ((++b) && (++c));
||
的优先级高于=
c = ((++a) || ((++b) && (++c)));
=
的优先级最低(c = ((++a) || ((++b) && (++c))));
||
短路和最低优先级运算符这一事实解释了结果。因为 ++
的优先级高于 &&
而 &&
的优先级高于 ||
,所以 ++a || ++b && ++c
的表达式树是:
|| -- left: ++a
-- right: && --left: ++b
--right: ++c
因此,为了计算表达式,C 首先考虑计算 ||
的规则,由 C11 标准中的 6.5.14 给出。具体来说:
6.5.14.4: Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares unequal to 0, the second operand is not evaluated.
||
短路的事实意味着它首先评估其左操作数,并且仅在左操作数为零时才评估其右操作数。因此,要计算表达式 ++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
为假且 ++b
为真,则必须评估 ++c
。但是,c = ...
和++c
之间没有序列点。由于表达式都修改 c
且中间没有序列点,因此行为未定义。有关此内容的进一步说明,请参阅