C ++中对运算符优先级的混淆

时间:2018-12-06 00:38:11

标签: c++ gcc visual-studio-2017 operator-precedence

说,在下面的测试表达式中:

int ggg9 = fggg2() + (fggg3() && fggg4() < fggg5() * fggg6());
//                 4          11         6         3

如果我们遵循operator precedence(在表达式下方的注释行中显示),则我认为将首先对parens中的表达式求值,然后将结果添加到fggg2()。 / p>

因此,我假设它将按以下顺序解决:

int r1 = fggg5() * fggg6(); //Precedence 3 (inside parens)
int r2 = fggg4() < r1;      //Precedence 6 (inside parens)
int r3 = fggg3() && r2;     //Precedence 11 (inside parens)
int ggg9 = fggg2() + r3;    //Outside of parens, so it's last

但是x86-64 gcc 8.2 resolves it这样:

enter image description here

(我将其转换回C ++)

    int i0;
    int r2 = fggg2();
    int r3 = fggg3();
    if(!r3) goto L13;
    int r4 = fggg4();
    int r5 = fggg5();
    int r6 = fggg6();
    int i1 = r5 * r6;
    if(r4 >= i1) goto L13
    i0 = 1;
    goto L14
L13:
    i0 = 0;
L14:
    int ggg9 = i0 + r2;

那么为什么&&运算符的优先级分别为11、3、6时似乎要先于*<进行评估?

最后,为什么通过首先评估fggg2()似乎并不关心parens? VS2017似乎最后评估了它。

据我所见,gcc编译器只是从左至右评估了所有这些功能,而与优先级无关。

3 个答案:

答案 0 :(得分:5)

您正在将优先级评估顺序混合在一起。

这是一个非常常见的混乱。可能是因为英语中的“ precede”一词具有时间含义。但这实际上是从排名层次结构(例如here)的意义上讲。

在更简单的表达式a() + b() * c()中,优先级告诉我们*运算符的操作数是b()c(),而+的操作数是a()以及相乘的结果。一无所有,一无所有。

函数a,b,c可能仍可以按任何顺序调用。

的确,*值计算必须在+值计算之前执行,因为我们需要知道前者的结果以便计算后者。

值计算是评估操作数的另一步骤。必须先计算运算符的操作数,然后再计算其值,但没有比这更严格的要求了。没有关于评估操作数的部分排序的规则。

+的左操作数可能在+的右操作数之前求值,即使右操作数由许多子表达式组成。编译器可能会评估所有“叶”操作数,将结果存储在堆栈中,然后执行值计算。

也不一定有严格的值计算顺序,例如在w() * x() + y() * z()中,*的两个值计算可能以任一顺序进行。


在您的代码中,&&运算符的确有特殊的排序限制(有时称为短路)。在开始评估右操作数之前,必须先评估左操作数。

优先级告诉我们&&的左操作数为fgg3(),而&&的右操作数为fggg4() < fggg5() * fggg6())。因此,要求在fgg3()fgg4fgg5中的任何一个之前调用fgg6。在示例中,对操作数的求值顺序没有其他限制。 fgg2可以随时出现,456可以以任何顺序排列,只要它们都位于3之后。 / p>

答案 1 :(得分:0)

您将运算符的优先级与求值顺序混淆了,虽然可以保证保留优先级,但不求值顺序,编译器可以自由选择顺序。

它可以首先在其他操作数的评估中间或之间评估fggg2()

答案 2 :(得分:0)

您忘记考虑&&运算符的短路评估。

&&运算符的左侧总是先于右侧进行求值。

为简化操作,必须对r3的前半部分求值,如果它的值为false,则不会对您称为r1r2的任何内容进行求值。

在C ++中需要进行短路评估。