也做个比较(2)

对于

6。 整数交换

Java: 
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.out.println(“x = ” + x + “; y = ” + y);

C#:
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.Console.WriteLine(“x = ” + x + “; y = ” + y);

输出结果一样

Java x = 0; y = 1984
C# x = 0; y = 1984

fancyf 在上个post的回复中建议这个是Bug,其实不然,因为根据Specifications,

x ^= y ^= x ^= y;

其运算是这么做的(起码当前版本是如此):

“…The order in which operands in an expression are evaluated, is left to right. [Example: For example, in F(i) + G(i++) * H(i), method F is called using the old value of i, then method G is called with the old value of i, and, finally, method H is called with the new value of i. This is separate from and unrelated to operator precedence. end example]…” (见C# Language Specification, 14.2;至于Java中的表达式运算次序,参考 Java Language Specification, 15.7)

^=处,即对于 a ^= expr ,做运算时,a = a ^ expr,右边的a用的是运算expr的值,这样

y ^= x ^= y;  ==> x=1984^2001 =>17, y = 2001 ^ 17 => 1984
x ^= y ^= x ^= y; ==> x = 1984 ^ 1984 => 0

让我们再来看一下对应下面C#编码的IL码,观察stack的变化

public class CleverSwap {
    public static void Main(string[] args) {
        int x = 1984;
        int y = 2001;
        x ^= y ^= x ^= y;
        System.Console.WriteLine(“x={0}, y={1}”,x,y);
    }
}

.method public hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       49 (0x31)
  .maxstack  4
  .locals init (int32 V_0,
           int32 V_1)
  IL_0000:  nop
  IL_0001:  ldc.i4     0x7c0  //stack: 0x7c0
  IL_0006:  stloc.0  //stack:  <==>x=0x7c0
  IL_0007:  ldc.i4     0x7d1 //stack: 0x7d1 
  IL_000c:  stloc.1  //stack:  <==>x=0x7c0,y=0x7d1
  IL_000d:  ldloc.0  //stack: 0x7c0 
  IL_000e:  ldloc.1  //stack: 0x7c0,0x7d1
  IL_000f:  ldloc.0  //stack: 0x7c0,0x7d1,0x7c0
  IL_0010:  ldloc.1  //stack: 0x7c0,0x7d1,0x7c0,0x7d1
  IL_0011:  xor   //stack: 0x7c0,0x7d1,0x11
  IL_0012:  dup   //stack: 0x7c0,0x7d1,0x11,0x11 
  IL_0013:  stloc.0  //stack: 0x7c0,0x7d1,0x11     <==>x=0x11,y=0x7d1
  IL_0014:  xor   //stack: 0x7c0,0x7c0     <==>x=0x11,y=0x7d1
  IL_0015:  dup   //stack: 0x7c0,0x7c0,0x7c0     <==>x=0x11,y=0x7d1
  IL_0016:  stloc.1  //stack: 0x7c0,0x7c0     <==>x=0x11,y=0x7c0
  IL_0017:  xor   //stack: 0x00     <==>x=0x11,y=0x7c0
  IL_0018:  stloc.0  //stack:  <==>x=0x00,y=0x7c0
  IL_0019:  ldstr      “x={0}, y={1}”
  IL_001e:  ldloc.0
  IL_001f:  box        [mscorlib]System.Int32
  IL_0024:  ldloc.1
  IL_0025:  box        [mscorlib]System.Int32
  IL_002a:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object,
                                                                object)
  IL_002f:  nop
  IL_0030:  ret
} // end of method CleverSwap::Main

至于C/C++,根据Joshua Bloch/Neal Gafter

“…… In C and C++, the order of expression evaluation is not specified. When compiling the expression x ^= expr, many C and C++ compilers sample the value of x after evaluating expr, which makes the idiom work. Although it may work, it runs afoul of the C/C++ rule that you must not modify a variable repeatedly between successive sequence points [ISO-C]. Therefore, the behavior of this idiom is undefined even in C and C++…..”

而Java/C#则明确规定了表达式中operand的evaluation次序,所以结果不同,起码当前版本是如此