对C++中运算符优先级的困惑

c00*_*0fd 0 c++ gcc operator-precedence visual-studio-2017

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

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

如果我们遵循运算符优先级(在表达式下面的注释行中显示),我会假设首先计算parens中的表达式,然后将结果添加到fggg2().

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

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
Run Code Online (Sandbox Code Playgroud)

但是x86-64 gcc 8.2 解决它是这样的:

在此输入图像描述

(我将它转换回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;
Run Code Online (Sandbox Code Playgroud)

那么,为什么&&运营商似乎之前进行评估*,然后<当他们的优先级为11,3,6,分别?

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

从我看来,gcc编译器只是从左到右评估所有这些函数,而不考虑优先级.

M.M*_*M.M 6

您将优先级评估顺序混为一谈.

这是一个非常常见的混乱.也许是因为英语中的"先行"这个词可以有时间含义.但实际上它意味着排名层次结构(例如这里).

在更简单的表达式中a() + b() * c(),优先级告诉我们运算*符的操作数是b()c(),以及+are 的操作数a()和乘法的结果.没有更多,也没有更少.

这些函数a,b,c可能仍以任何顺序调用.

这是事实,该值计算*,必须在之前完成值计算+,因为我们需要知道前者的结果,以计算后者.

值计算是评估操作数的不同步骤.必须在计算值之前评估运算符的操作数,但没有比这更严格的要求.关于评估操作数的部分排序没有规则.

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

不一定存在严格的值计算顺序,例如w() * x() + y() * z(),两个值计算*可以以任一顺序发生.


在您的代码中,&&操作员确实有一个特殊的排序限制(有时称为短路).必须在开始评估右操作数之前评估左操作数.

优先告诉我们的左操作数&&fgg3(),和右边的操作数&&fggg4() < fggg5() * fggg6()).因此,要求fgg3()在任何之前调用fgg4,fgg5并且fgg6.在您的示例中,对操作数的评估顺序没有其他限制.在fgg2可能发生在任何时间,4,5,6可以以任意顺序,只要他们毕竟是3.