对于
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次序,所以结果不同,起码当前版本是如此