Puzzle 07: Swap Meat
用位运算交换整数失效
以下代码执行后x, y的值为多少?
int x = 1984; // 0x7c0
int y = 2001; // 0x7d1
x ^= y ^= x ^= y;
下面来一段貌似正确的演算:
x = 1984: 00000000000000000000011111000000
y = 2001: 00000000000000000000011111010001
x ^= y ^= x ^= y
1. x ^= y
00000000000000000000011111000000 x
^ 00000000000000000000011111010001 y
00000000000000000000000000010001 x
2. y ^= x
00000000000000000000011111010001 y
^ 00000000000000000000000000010001 x
00000000000000000000011111000000 y
3. x ^= y
00000000000000000000000000010001 x
^ 00000000000000000000011111000000 y
00000000000000000000011111010001 x
x = 00000000000000000000011111010001 = 2001
y = 00000000000000000000011111000000 = 1984
但事实上, 以上代码片段运行以后, x = 0, y = 1984.
因为在Java中, 按照书中的说法:
Java语言规范描述到: 操作符的操作数是从左向右求值的. 为了求表达式 x ^= expr的值, x的值是在计算expr之前被提取的, 并且这两个值异或结果被赋给变量x. 在以上程序中, 变量x的值被提取了两次--每次在表达式中出现时都提取一次--但两次提取都发生在所有的赋值操作之前.
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 evaluate, and the exclusive OR of these two values is assigned to the variable x [JLS 15.26.2]. In the above program, the variable x is sampled twice -- once for each appearance in the expression -- but both samplings occur before any assignments.
真实的演算过程应该如下:
1. int tmp1 = x;
2. int tmp2 = y;
3. int tmp3 = x ^ y;
4. x = tmp3;
5. y = tmp2 ^ tmp3 = y ^ (x ^ y) = x
6. x = tmp1 ^ y = x ^ x = 0
附
- JLS 15.7 Evaluation Order
- JLS 15.26.2 Compound Assignment Operators
- EJ Item 37