如果括号的优先级更高,那么为什么首先解决增量运算符?

2022-08-31 23:45:10

我有一行代码,

int a = 10;
a = ++a * ( ++a + 5);

我的预期产量是,但我得到了187。尽管我知道内部的增量运算符是首先要解决的,那么为什么首先解决外部的增量运算符呢?12 * (11 + 5) = 192()


答案 1

表达式从左到右计算。括号(和优先级)只是表示分组,它们不表示评估的顺序。

所以

 11 * (12 + 5)
++a   ++a

等于

187

答案 2

引用Eric Lippert的博客

算术表达式的计算由三组规则控制:优先规则、关联性规则和顺序规则。

优先规则描述当表达式混合不同类型的运算符时,应如何将不足的伪装表达式括起来。

关联性规则描述当表达式具有一堆相同类型的运算符时,应如何将不足的伪装表达式括起来。

计算规则的顺序描述表达式中每个操作数的计算顺序。

较高的优先级会导致使用运算符对操作数进行分组,并不意味着操作数的计算。它是计算顺序,它决定了表达式中子表达式的计算顺序。


更新:

正如我所看到的,许多程序员都认为这种说法

a = ++a * ( ++a + 5);  

将调用未定义的行为。是的,如果不能保证运算符的操作数的求值顺序,它将调用 UB。

但是在java编程语言的上下文中,情况并非如此。它在java(以及C#)中具有明确定义的行为。Java 语言规范指出:

15.7. 评估顺序

Java编程语言保证运算符的操作数看起来是按特定的评估顺序(即从左到右)计算的

例 15.7.1-1.首先评估左侧操作数

在下面的程序中,运算符具有一个左操作数(包含对变量的赋值)和一个右操作数(包含对同一变量的引用)。引用生成的值将反映分配首先发生的事实。*

class Test1 {
    public static void main(String[] args) {
        int i = 2;
        int j = (i=3) * i;
        System.out.println(j);
    }
}

此程序生成输出:

9

不允许对 * 运算符进行评估以产生 6 而不是 9

但是,Java规范仍然明确指出不要编写这样的代码:

建议代码不要严重依赖此规范。当每个表达式最多包含一个副作用(作为其最外层的操作)时,以及当代码不依赖于由于表达式的从左到右计算而产生的确切异常时,代码通常更清晰。


推荐