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

  1. JLS 15.7 Evaluation Order
  2. JLS 15.26.2 Compound Assignment Operators
  3. EJ Item 37