如果括号具有更高的优先级,那么为什么增加算子先解决?

我有一个单行代码,

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

我的预期产出是12 * (11 + 5) = 192 ,但我有187 。 就我所知,内部()内的增量操作符首先要解决,那么为什么外面的一个先解决?

expression式从左到右进行评估。 括号(和优先级)只是表示分组,并不表示评估的顺序。

所以

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

等于

 187 

引用Eric Lippert的博客 :

算术expression式的评估由三组规则控制:优先规则,关联规则和顺序规则。

优先规则描述了当expression式混合不同types的运算符时,如何将不完整的expression式加括号。

关联性规则描述了当expression式包含一堆相同types的操作符时,如何将不恰当的expression式加括号。

评估规则的顺序描述了评估expression式中每个操作数的顺序。

更高的优先级导致操作数与运算符分组,并不意味着对操作数的评估。 决定expression式中子expression式评估顺序的评估顺序。


更新:

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

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

会调用未定义的行为。 是的,如果没有运营商操作数评估顺序的保证,它会调用UB。

但是在java编程语言的情况下这是不正确的。 它在java(以及C#)中有良好的行为。 Java语言规范指出:

15.7。 评估顺序

Java编程语言保证操作符的操作数看起来是按照特定的评估顺序,即从左到右进行评估的

例15.7.1-1。 左手操作数首先被评估

在下面的程序中, *运算符的左侧操作数包含对variables的赋值,右侧的操作数包含对同一variables的引用。 参考文献所产生的价值将反映出这项工作首先发生的事实。

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

这个程序产生输出:

 9 

不允许评估*运算符产生6而不是9

但是,java规范还是明确指出不写这样的代码:

build议代码不要严格依赖于这个规范 。 当每个expression式至多包含一个副作用时,代码通常会更清晰,作为其最外层的操作,并且代码并不完全依赖于由expression式的左到右评估而产生的exception。

从这个片段

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

有时候,最简单的解决方法是使用javap来理解评估顺序:

  0: bipush 10 // push 10 onto the stack (stack={10}) 2: istore_1 // store 10 into variable 1 (a = 10, stack={}) 3: iinc 1, 1 // increment local variable 1 by 1 (a = 11, stack={}) 6: iload_1 // push integer in local variable 1 onto the stack (a = 11, stack = {11}) 7: iinc 1, 1 // increment local variable 1 by 1 (a = 12, stack={11}) 10: iload_1 // push integer in local variable 1 onto the stack (a = 12, stack = {12, 11}) 11: iconst_5 // load the int value 5 onto the stack (a = 12, stack = {5, 12, 11}) 12: iadd // add 5 and 12 (a = 12, stack = {17, 11}) 13: imul // multiply 17 and 11 (a = 12, stack = {}) 
  1. a递增1.(第3行)// a = 11
  2. a递增1.(第7行)// a = 12
  3. 添加5 (第12行)// a = 17
  4. 1117 (13行)// a = 187

(10 + 1 + 1 + 5)* 11 = 187

括号的作用是控制哪些计算值用作后续操作的操作数。 它们控制操作的执行顺序,只有在操作数达到操作数后才能对操作进行评估。 考虑expression式:

 (a()+b()) * (c()+d()) a() + (b()*c()) + d() 

括号不需要(在Java中不能)影响a(),b(),c()和d()被调用的顺序。 它们可能会影响乘法是在d()被调用之前还是之后执行的,但是仅在极less数情况下(例如d()调用Java本地接口,以Java方式不知道的方式改变乘法中使用的数字舍入模式约)将代码有任何方式知道或关心乘法是否在d()之前或之后执行。

否则,重要的是,在第一种情况下,一个加法操作将作用于()和b(),另一个作用于c()和d()。 乘法将作用于()+ b()和c()+ d()。 在另一种情况下,第一次乘法将作用在b()和c()上,第一次加上()和上述乘积,第二次加上第一次和和d()。

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

以上types的expression式总是以左至右的方式来评估它是C还是JAVA

在这种情况下,它正在解决像这样的11 *(12 + 5),这导致11 * 17 = 187 // wrt java

但如果我们解决与C语言相同的expression式

那么答案会随着评估方式的变化而变化

在第一个预先增加/预先递减的情况下发生,所以如果在expression式中没有preinc / dec之前的“N”,那么inc / dec将首先发生“N”次

那么在expression式中的每个variables的出现中将代入相同的值并且计算expression式值,并且之后发生增量/减量

即a递增到11,然后再递增12,因为在expression式中有两个递增,然后expression式被评估为

12 *(12 + 5)= 12 * 17 = 204 //关于C语言