优先级和求值顺序

7
我不理解这个程序的输出:
#include<iostream>
using namespace std;
int main()
{
    int x = 1 , y = 1, z = 1;
    cout << ( ++x || ++y && ++z ) << endl; //outputs 1;
    cout << x << " " << y << " " << z ;  //x = 2 , y = 1 , z = 1;
    return 0;
}

输出:

1
2 1 1

如果首先评估||,则此输出没有问题。但是,文章指出&&的优先级高于||,因此必须首先对其进行评估。 如果是这样,则根据我的理解,输出应为:
1
1 2 2
++y && ++z 会被评估为 true,因此不会评估 ++x

9
优先级 != 求值顺序。 - Oliver Charlesworth
那么我如何确定评估顺序呢?感谢您的建议。 - shiva
我看到了,谢谢 @molbdnilo - Khalil Khalaf
有一篇由Eric Lippert撰写的好文章,它解释了“优先级,结合性和评估顺序之间的区别”(https://blogs.msdn.microsoft.com/ericlippert/2008/05/23/precedence-vs-associativity-vs-order/)。它更注重C#,但也涉及到了C ++。只有一个问题:他说在C ++中,计算顺序是自由的(不像C#,在C#中它是严格从左到右)。好吧,有例外情况:布尔运算符AND和OR需要从左到右,以便可以应用短路,就像这种情况一样。 - Fabio says Reinstate Monica
5个回答

9
让我们把多余的括号放进去:
( ++x || (++y && ++z) )
然后很容易看出,只有当++x为0时,(++y && ++z)才会被评估。所以可以看出,无论运算符优先级如何,||的短路特性意味着右侧只有在左侧为0时才会被评估。
(如果右侧被评估,请注意只有在++y不为0时才会评估++z。)

2
这并不真正回答问题-求值顺序不是由优先级确定的。 - Oliver Charlesworth
@OliverCharlesworth:是的,我认为你是正确的。我已经修改了这个答案。 - Fitzwilliam Bennet-Darcy

9

&&的优先级高于||,因此必须先进行求值。

不是这样的。 运算符优先级 只决定当解析表达式时运算符将如何更紧密地绑定到其参数(就像括号一样),它并不影响求值顺序。 在这种情况下,只是意味着++x || ++y && ++z 将被解析为(++x) || (++y && ++z),而不是(++x || ++y) && (++z)

请注意,operator|| 的关联性是从左到右的,因此++x将首先被评估,而(++y && ++z)将不会被评估,因为具有短路求值的特点(除了重载的 operator||)。


7
"Precedence" 影响的是分组,而不是顺序,这意味着如果关于一个操作数“属于”哪个运算符存在歧义,则优先级较高的运算符将首先使用它。
由于涉及两个二元运算符,因此可以有两种解读表达式的方式。作为树状结构,它们将是:
    and
    /\
   or ++z       [(++x || ++y) && ++z]
  / \
++x ++y 


   or
   /\
++x  and       [++x || (++y && ++z)]
     / \
  ++y ++z

优先级规则确定在C++中选择后者的树,因为中间操作数++y&&分组,而不是与||分组。
这些运算符的“短路”意味着评估必须从最左侧叶子开始(每个运算符必须首先评估其左腿,然后如果需要,再评估其右腿)。
因此,++x首先被评估,只有当++x为零时,||才继续执行其右腿,但实际上它不为零。
(正如可以从精美而富有艺术感的图表中看出的那样,无论&&||的相对优先级如何,++x必须首先进行评估。)

1
这个表达式
 ++x || ++y && ++z

等同于表达式

++x || ( ++y && ++z )

而不是这样
 ( ++x || ++y ) && ++z

如果逻辑 OR 表达式的第一个操作数被评估为 true(就像您的示例一样),那么第二个操作数 ( ++y && ++z ) 就不会被评估。


0

( ++x || (++y && ++z )) - 可以看作是布尔值 - 只有 ++x 被计算。它的 int 值为 2,布尔值为 1(真)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接