这段代码
int a = 100, b = 7;
a^=b^=a^=b;
Console.WriteLine(a + " " + b);
的
作用
意图应该是交换两个整数,然而运行结果出乎意料:
0 100
而
a ^= b;
b ^= a;
a ^= b;
正确地交换了a和b。在VS.NET 2003和VS 2005 Beta2中的C#运行结果一样。
经检查,所生成的IL代码没有问题:
怪我没有仔细看,IL代码与最后所生成的汇编代码一致。单击这里见思归的详细分析。
L_0000: ldc.i4.s 100
L_0002: stloc.0
L_0003: ldc.i4.7
L_0004: stloc.1
L_0005: ldloc.0
L_0006: ldloc.1
L_0007: ldloc.0
L_0008: ldloc.1
L_0009: xor
L_000a: dup
L_000b: stloc.0
L_000c: xor
L_000d: dup
L_000e: stloc.1
L_000f: xor
L_0010: stloc.0
L_0011: ldloc.0
L_0012: box int32
L_0017: ldstr " "
L_001c: ldloc.1
L_001d: box int32
L_0022: call string string::Concat(object, object, object)
L_0027: call void [mscorlib]System.Console::WriteLine(string)
L_002c: ret
但是
最后生成的汇编
却有问题
是:
1: int a = 100, b = 7;
00000000 push ebp
00000001 mov ebp,esp
00000003 sub esp,18h
00000006 push edi
00000007 push esi
00000008 push ebx
00000009 xor edi,edi
0000000b xor ebx,ebx
0000000d mov edi,64h
00000012 mov ebx,7
2: a ^= b;
00000017 xor edi,ebx
3: b ^= a;
00000019 xor ebx,edi
4: a ^= b;
0000001b xor edi,ebx
5: a^=b^=a^=b;
0000005e mov esi,edi
00000060 xor edi,ebx
00000062 xor ebx,edi
00000064 xor esi,ebx
00000066 mov edi,esi
这是个Bug吗?最初我认为是这样的,而且还把这个“Bug”提交到了MSDN Product Feedback Center。但思归给出的C# Language Specification, 14.2让我如梦方醒。全文在这里。
不过
在反馈中心得到的回复
又令我迷惑不解:
看来是JIT的Bug。我昨天
提交了这个Bug,今天已经得到了答复:
This has been fixed in Whidbey RTM.
既然不是Bug,怎么说“has been fixed”了呢?
在MSDN Product Feedback Center得到的答复也非常中肯,还给了很好的建议:
Actually the behaviour is correct and by design.
The mistake in you logic is that you assume that, because the expression is evaluated right-to-left for precedence, the variable locations are also taken from right to left at runtime.
This only goes to show that you should parenthesize your code well, use well-named temporary variables abundantly and generally not write code that is so confusing that not even you yourself knows what it means :-)
Mads Torgersen
正是因为我做了错误的假设C#中的行为应该跟C++中的行为一样,发现问题后又没有去查C# Language Specification,才闹了这么一幕笑话。一定吸取教训!
修改于2005年8月22日 23:56
修改于2005年8月29日 01:55