int x = 4;
x+=x-=x-x--;
java:output 8 The King of Coding
jvm指令执行的顺序
public class b extends java.lang.Object{
public b();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4 // 常量4压栈
1: istore_1 // 出栈, 并赋值给第一个变量, 也就是x
2: iload_1 // x压栈
3: iload_1 // x压栈
4: iload_1 // x压栈
5: iload_1 // x压栈
6: dup // 赋值栈顶元素, 并压栈
7: iconst_1 // 常量1压栈
8: isub // nexttop - top, 也就是(4-1), 并将结果(3)压栈
9: istore_1 // 3出栈, 赋值给x
10: isub // nexttop - top, 也就是(4-4), 并将结果(0)压栈
11: isub // nexttop - top, 也就是(4-0), 并将结果(4)压栈
12: dup // 赋值栈顶元素, 并压栈
13: istore_1 // 4出栈, 复制给x
14: iadd // nexttop + top, 也就是(4+4), 并将结果(8)压栈
15: istore_1 // 8出栈, 复制给x, 所以结果是8
16: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
19: iload_1
20: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
23: return
}
C++ Assemble Instruction
8: int x=4;
00401058 mov dword ptr [ebp-4],4
9: x+=x-=x-x--;
0040105F mov eax,dword ptr [ebp-4]
00401062 sub eax,dword ptr [ebp-4]
00401065 mov ecx,dword ptr [ebp-4]
00401068 sub ecx,eax
0040106A mov dword ptr [ebp-4],ecx
0040106D mov edx,dword ptr [ebp-4]
00401070 add edx,dword ptr [ebp-4]
00401073 mov dword ptr [ebp-4],edx
00401076 mov eax,dword ptr [ebp-4]
00401079 sub eax,1
0040107C mov dword ptr [ebp-4],eax
phenixsen's explanation
这是因为操作数的求值顺序不同而引起的问题,在《java解惑》的Puzzle 7: Swap Meat里也提到了这个问题:
It is guaranteed not to work in Java. The Java language specification says that operands of operators are evaluated from left to right [JLS 15.7]. To evaluate the expression x ^= expr, the value of x is sampled before expr is evaluated, and the exclusive OR of these two values is assigned to the variable x [JLS 15.26.2].
也就是说对于 ^= , +=, -= 这样的操作符,操作数是在右部表达式求值之前就确定的,所以实际上,我们可以把 x += expr, 写成是 x = x + expr, 更清楚一点就是 temp = x, x = temp + expr. 也就是说无论expr对x做了什么更改, 参与+运算的这个x的值是之前就确定的, 根据这样的方法, 可以把 x+=x-=x - x-- 写成:
temp1 = x; // temp1 = 4;
temp2 = x; // temp2 = 4;
temp3 = x; // temp3 = 4;
temp4 = x--; // temp4 = 4 , x = 3;
temp5 = temp3 - temp4; // temp5 = 0;
x = temp2 - temp5 // x = 4;
x = temp1 + x; // x = 8;
而在C/C++中, 操作数的求值顺序是没有规定的, 一般来说, c/c++在求值 x += expr这样的表达式时, 作为操作数的x的值是在计算完expr的值之后才进行抽取(sample)的, 这时候, expr对x的改变就会起作用了, 这样, x += expr 可以被写成是 temp1 = expr, temp2 = x, x = temp1 + temp2. 而 x += x -= x - x-- 的求值就是:
这里还要涉及到一个后缀++和--操作的问题,在C++里面,表达式里的这个++和--操作是在最后面来做的,而在java里面是在值被用到之前来做的。所以这里的
x+=x-=x-x--实际上的运算过程应该是:
x = 4; //x = 4;
temp1 = x; // temp1 = 4;
temp2 = x - temp1 // temp2 = 0;
temp3 = x - temp2; // temp3 = 4;
x = temp3; // x = 4;
temp5 = x + temp3; // temp5 = 8;
x = temp5; // x = 8;
x--; // x = 7;
可以验证一下这个结论,比如下面的程序:
int x = 4;
int j = (x++) + (x++);
在java里面,j最后是9, 而在c里面,j最后是8;
就是这样.