12

据我所知,逻辑运算符&&的优先级高于||. 在运行代码时:

#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. 然后评估其右侧表达式(如果需要)

我错了吗?

4

4 回答 4

13

||运算符短路- 如果其第一个操作数的计算结果为真(非零),它不会计算其第二个操作数。

对于 也是如此&&,如果第一个操作数为假,它不使用第二个操作数。这是一种可能的优化,因为任何布尔值 OR true 都是 true,类似地,任何布尔值 AND false 总是 false。


好的,所以您将优先级与评估顺序混淆了。这里根本没有什么矛盾的:

++i || ++j && ++k

被分组为

(++i) || (++j && ++k)

因为&&具有更高的优先级。但是 OR 操作的 LHS 为真,因此整个 RHS及其 AND 操作被丢弃,它不被评估。


对于您在编辑中的注释:是的,您错了:运算符优先级仍然与评估顺序不同。这只是分组。

于 2013-07-02T18:08:14.470 回答
10

首先,正如您自己所说,&&具有更高的优先级,这意味着操作数分组应该是

 (++i) || (++j && ++k)

为什么你说“根据运算符优先级”应该(++i || ++j) && (++k)是我不清楚的。这与你自己所说的相矛盾。

其次,运算符优先级与评估顺序绝对无关。运算符优先级规定了运算符及其操作数之间的分组(即运算符优先级表示哪个操作数属于哪个运算符)。

同时,评估顺序是完全不同的故事。它要么保持未定义,要么由完全不同的规则集定义。在||and&&运算符的情况下,评估顺序确实定义为从左到右(尽可能强制提前完成)。

因此,运算符优先级规则告诉您分组应该是

 (++i) || ((++j) && (++k))

现在,评估顺序规则告诉您,首先我们评估++i,然后(如果需要)我们评估++j,然后(如果需要)我们评估++k,然后我们评估&&,最后我们评估||

于 2013-07-02T18:12:24.533 回答
9

你说:

只有当++i || ++j && ++k这样评估时才有可能:

(++i) || (++j && ++k)

但是,根据运算符优先规则,它应该被评估为:

(++i || ++j) && (++k)

第一个分组是正确的,因为 的优先级&&高于 的优先级||。然后表达式作为一个整体计算 的 LHS ||,具有递增的副作用i,其计算结果为真。这意味着||&&表达式)的 RHS 根本不会被评估,因为不需要它来确定整个表达式的真实性。

所以,编译器是正确的;您以某种方式误解了优先级。


为什么第一个分组是正确的?根据第一个分组||的优先级高于&&。我怎么了?

您似乎不了解优先级,或者您不了解优先级与评估顺序的相互作用。第一个分组给予 更高的优先级&&

如果有a + b * c, where*的优先级高于+,那么它被评估为a + (b * c),不是吗?变化+||*&&,表达式是同构的,解释是相似的。

算术表达式和逻辑表达式的最大区别在于逻辑表达式的操作数必须从左到右进行计算,而算术表达式的操作数则不需要。编译器可以在评估b * c之前进行评估a(但必须b * c在进行加法之前进行评估)。相比之下,在逻辑表达式 ( a || b && c) 中,编译器必须在评估a之前评估b && c,当a结果为真时,它不能评估bor c,更不用说 了b && c

于 2013-07-02T18:14:17.153 回答
3

既然你误解了优先级,让我们试着用一个数学例子来澄清它。乘法和除法的优先级高于加法和减法。这意味着这个表达式:

a + b * c - d / e

可以这样写:

a + (b * c) - (d / e)

由于您正确地指出&&具有高于 的优先级||,因此此表达式:

i || j && k

可以这样写:

i || (j && k)

如果有帮助,您可以将其视为“优先级最高的操作首先被括号括起来”。

(但优先级与评估不同- 如果i为真,则(j && k)永远不会被评估。)

于 2013-07-02T18:35:01.903 回答