#include <stdio.h>
int main(void) {
int a = 0, b = 0, c = 0;
++a || ++b && ++c;
printf("%d %d %d", a, b, c);
return 0;
}
通过gcc 8.1.0编译,输出结果为1
,0
,0
。在此情况下,&&
的优先级应该高于||
。
为什么b
和c
仍然是0
?
#include <stdio.h>
int main(void) {
int a = 0, b = 0, c = 0;
++a || ++b && ++c;
printf("%d %d %d", a, b, c);
return 0;
}
通过gcc 8.1.0编译,输出结果为1
,0
,0
。在此情况下,&&
的优先级应该高于||
。
为什么b
和c
仍然是0
?
表达式++a || ++b && ++c
被分组为++a || (++b && ++c)
。但是,只有在++a
为0
时,||
右侧的表达式才会被计算,而这种情况不会发生。
||
的左侧先被评估。 - Bathsheba||
之前应该先对其进行求值,但++a
不是||
,而是其操作数。 - chris这里有三个问题:
优先级顺序意味着 ++a || ++b && ++c
被看作是 ++a || (++b && ++c)
。
然而,由于逻辑运算符的短路要求,首先会评估 ++a
。只有在它的结果为 false
时才会评估 (++b && ++c)
。在您的情况下,++a
的结果为 true
。因此,(++b && ++c)
永远不会被评估。
||
(以及逻辑 AND 运算符 &&
)是少数执行短路操作的运算符之一。因为4 与按位
|
运算符不同,||
运算符保证从左到右进行求值;如果计算第二个操作数,则在第一个和第二个操作数的计算之间存在一个序列点。 如果第一个操作数与 0 不相等,则不计算第二个操作数。
++a
的值为1,所以||
运算符的结果保证为1,右侧不会被计算。另外,由于&&
的优先级高于||
,所以||
运算符的右侧是++b && ++c
,这意味着++b
和++c
都不会被计算。就优先级而言,x || y && z
的作用就像x + y * z
一样:第二个运算符比第一个结合得更紧密,这些表达式分别等同于x || (y && z)
和x + (y * z)
。
问题中b和c没有增加的原因是,除了优先级外,逻辑运算还会短路:一旦你已经足够远地知道结果,剩下的表达式就会被跳过。双管齐下运算符||
和&&
左到右计算它们的参数,所以在a() || b()
和a() && b()
中,调用a()
发生在调用b()
之前。
a()
返回 true
,那么在表达式 a() || b()
中,调用 b()
将不会被执行,因为它不会影响结果。同样,如果 a()
返回 false
,则在表达式 a() && b()
中,调用 b()
将不会被执行。b
和 c
的递增不会被执行,因为 ++a
产生非零值,所以表达式的结果是 true
,无需评估 ++a
后的任何内容。运算符优先级与求值顺序无关。优先级是为了将具有不同类型的运算符与它们的操作数分组而设置的优先级。
因此,表达式
++a || ++b && ++c;
将被评估为
++a || (++b && ++c);
逻辑与和逻辑或运算符构成序列点,因此保证了它们的操作数按照从左到右的顺序进行评估。
评估顺序:
顺序
......
- 如果在子表达式 E1 和 E2 之间存在序列点,则 E1 的值计算和副作用都先于 E2 的每个值计算和副作用发生。
规则
.....
2) 在以下二元运算符的第一个(左)操作数评估后、第二个(右)操作数评估前,存在序列点:&&(逻辑与)、||(逻辑或)和,(逗号)。
逻辑或运算(expr1 || expr2)
采用短路行为。也就是说,如果expr1
是逻辑1
(true)
,则不会评估expr2
。
a
,b
和c
的初始值为0
。在表达式中:
++a || ++b && ++c;
++a
-> 前缀自增 a
。
这意味着表达式++a
的值是a
的递增值,即1
。由于||
运算符采用短路行为,因此||
的右侧表达式不会被评估。因此,您将获得输出-1 0 0
。
++a
更改为a++
。1
,但表达式的值是递增操作之前操作数的原始值。因此,a++
将被评估为0
,由于短路行为,||
运算符的右侧表达式(++b && ++c
)将被评估。
逻辑AND运算符(expr1 && expr2
)也采用短路行为。使用逻辑短路,仅当第一个操作数expr1
不能完全确定结果时,才会评估第二个操作数expr2
。也就是说,只有当expr1
是逻辑1
(true)
且++b
将导致1
时,才会评估expr2
。所以,如果你这样做。
a++ || ++b && ++c;
^^^
1 1 1
。