&&和 ||运营商
我遇到了这段代码:
int main()
{
int i=1,j=2,k=0,m=0;
m = ++i || ++j && ++k;
printf("%d %d %d %d %d",i,j,k,m);
}
程序返回 2 2 0 1...
。为什么?
&&
的优先级高于 ||
,因此 ++j && ++k
应该首先被评估。因此我期望 j=3
和 k=1
。它将返回 true,因此 ||
变为 true,因此不应评估 ++i
。但它的作用却相反。
我希望其他人向我解释。
I came across this code:
int main()
{
int i=1,j=2,k=0,m=0;
m = ++i || ++j && ++k;
printf("%d %d %d %d %d",i,j,k,m);
}
The program returns 2 2 0 1...
. Why?
&&
has a higher priority than ||
so ++j && ++k
should be evaluated first. Hence I would expect j=3
and k=1
. It will return true hence ||
becomes true so ++i
shouldn't be evaluated. But it works other way around.
I would like others to explain to me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(11)
基本上,||
的意思是,“如果您收到了真实的内容,则返回该内容,否则,返回之后发生的任何内容。”因此,唯一需要评估的是m = (++i != 0)
。这意味着“增加 i,将 m 分配给与 0 相比的 i 值,中断”。
更具体地说,这是正在发生的事情:
i = 1;
i = i + 1;
if( i ) {
m = 1;
}
else { // who cares, this will never happen.
j = j + 1;
if( j ) {
k = k + 1;
m = (k != 0); // 1
}
else {
m = 0;
}
}
在 C 语言中,您需要注意两个不同的问题:运算符优先级和求值顺序。
运算符优先级决定了哪个运算符首先计算其操作数,以及哪些操作数属于哪个运算符。例如,在表达式 a + b * c
中,运算符 * 的运算符优先级高于 +。因此,表达式将被计算为
a + (b * c)
C 语言中的所有运算符都具有确定性优先级,并且它们在任何编译器上都是相同的。
求值顺序决定首先求值的操作数。请注意,子表达式也是操作数。确定运算符优先级后应用计算顺序。如果上面的 a+b*c 示例具有从左到右的求值顺序,则操作数本身将按 a、b、c 的顺序求值。例如,如果操作数是函数调用,则函数 a()、b() 和 c() 将按该顺序执行。本例中的所有操作数都需要进行计算,因为它们都已被使用。如果编译器可以确定某些操作数不需要计算,则可以将它们优化掉,无论这些操作数是否包含副作用(例如函数调用)。
问题在于,操作数的求值顺序通常是未指定的行为,这意味着编译器可以自由地从左到右或从右到左求值,而我们无法知道或假设任何事情关于它。对于 C 中的大多数操作数都是如此,除了少数例外情况,其中评估顺序始终是确定性的。这些是运算符 || 的操作数&& ?: ,
,其中求值顺序保证为从左到右。 (当使用正式的 C 语言语义时,人们说在左运算符和右运算符的求值之间存在一个序列点。)
因此对于具体示例 m = ++i || ++j && ++k
。
- 一元前缀 ++ 运算符具有最高优先级,将运算符 i、j 和 k 绑定到它们。这个语法非常直观。
- 二进制 &&运算符具有第二高优先级,将运算符
++j
和++k
绑定到它。因此该表达式等价于m = ++i || (++j && ++k)
。 - 二进制||运算符具有第三高优先级,将运算符
i++
和(j++ && ++k)= 绑定到它。
- 赋值运算符 = 具有最低优先级,绑定运算符
m
和++i || (++j && ++k)
到它。
此外,我们可以看到 ||和 &&运算符是保证计算顺序从左到右的运算符之一。换句话说,如果 || 的左操作数运算符被评估为 true,编译器不需要评估正确的操作数。在具体示例中,++i
始终为正数,因此编译器可以执行相当大的优化,有效地将表达式重新构造为 m = ++i;
如果i
在编译时未知,编译器将被迫计算整个表达式。然后表达式将按以下顺序求值:
- &&优先级高于 ||,因此开始评估 &&操作员。
- &&运算符保证操作数的求值顺序是从左到右,因此首先执行 ++j。
- 如果 ++j 的结果为真(大于零),并且只有这样,才评估正确的运算符:执行 ++k。
- 存储 ++j && 的结果++k 在临时变量中。我在这里将其称为
j_and_k
。如果 ++j 和 ++k 均为正数,则j_and_k
将包含值 1(真),否则为 0(假)。 - ||运算符保证操作数的求值顺序是从左到右,因此首先执行 ++i。
- 如果 ++i 为假(零),并且只有在那时,才计算正确的运算符“
j_and_k
”。如果其中一个或两个均为正,则 || 的结果运算符为 1(真),否则为 0(假)。 - 根据结果,m 被分配值 1 或 0。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
具有更高的优先级并不意味着它首先被评估。这只是意味着它结合得更紧。在该示例中,该表达式相当于:
++i || (++j && ++k)
。首先计算的是++i
因为||
从左到右计算。仅当计算结果为 false 时,++j && ++k
被评估,因为||
是短路的。Having higher precedence does not mean it gets evaluated first. It just means it binds tighter. In that example, that expression is equivalent to:
++i || (++j && ++k)
. What gets evaluated first is++i
because||
evaluates left to right. Only if that evaluates to false will++j && ++k
be evaluated because||
is short-circuiting.