代码之家  ›  专栏  ›  技术社区  ›  c00000fd

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

  •  0
  • c00000fd  · 技术社区  · 6 年前

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

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

    如果我们跟着 operator precedence (在表达式下面的注释行中显示)我假设首先对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
    

    但是 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() 第一?VS2017似乎是最后一次评估。

    据我所见, gcc 编译器简单地从左到右计算所有这些函数,而不考虑优先级。

    3 回复  |  直到 6 年前
        1
  •  5
  •   M.M    6 年前

    你搞混了 优先 具有 估价顺序 .

    这是一个很常见的困惑。也许是因为英语中“先于”这个词有时间的含义。但实际上,它的意思是一种等级制度(例如 here )

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

    功能 a,b,c 可能所有人都会以任何顺序被召唤。

    的确, 价值计算 属于 * 必须在 价值计算 属于 + 因为我们需要知道前者的结果才能计算后者。

    值计算是计算操作数的另一个步骤。运算符的操作数必须在其值计算之前进行计算,但没有比这更严格的要求。对于计算操作数的部分排序没有规则。

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

    也不一定有严格的价值计算顺序,例如 w() * x() + y() * z() ,的两个值计算 * 可能按任意顺序发生。


    在你的代码中 && 运算符有特殊的排序限制(有时调用 短路 )在开始计算右操作数之前,必须计算左操作数。

    这个 优先 告诉我们的左操作数 && fgg3() ,和的右操作数 && fggg4() < fggg5() * fggg6()) . 所以这是一个要求 FGG3() fgg4 , fgg5 fgg6 . 在您的示例中,对操作数的计算顺序没有其他限制。这个 fgg2 可能随时发生,并且 4 , 5 , 6 只要他们都在找,就可以有任何顺序 3 .

        2
  •  0
  •   Sam Varshavchik    6 年前

    你忘了在短路评估中考虑 && 操作员。

    的左侧 && 操作员总是在右侧之前进行评估。

    在尝试简化操作时, r3 必须进行计算,如果计算结果为false,则不计算您所调用的 r1 r2 将被评估。

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

        3
  •  0
  •   Jans    6 年前

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

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