你真的了解a ^= (b ^= (a ^= b))吗?

引子:今天早上早早醒来无事,上园子依次看到

[C#] int与System.Int32有什么区别

理解C#中的System.Int32和int:并非鸡和鸡蛋

异或运算的一个问题,疑似C#编译器的Bug?

其中最后一篇 引起了我的好奇,难道CSC还真有bug?我来看看。

其实就是很简单的一个程序,

 

1  int  a  =   2 ;
2  int  b  =   9 ;
3  ^=  (b  ^=  (a  ^=  b));
4  Console.WriteLine( " {0}, {1} " , a.ToString(), b.ToString());

 

就是运行最后的结果是:

0,2

不是预期的9,2,后面的评论只是说a ^= (b ^= (a ^= b))相当于2 ^= (9 ^= (2 ^= 9)),具体的也没说明具体的原因是什么。

首先说明,托管代码在运行,主要用到3种形式的内存:

1.Managed Heap:动态内存分配的地方,由GC来管理,整个进程公用一个托管堆

2.Call Stack:每个thread都有自己的call  stack,每call一个方法,就会增加一个方法帧,方法执行完毕,则帧失效。帧记录了方法的参数,返回地址,局部变量

3.Evaluation Stack:同样每个thread都有自己的evaluation  stack,我们经常说的虚拟堆栈,就是这个。

下面是上述代码的IL:

 

 1  .method   private   hidebysig  static  void  Main( string [] args)  cil   managed
 2  {
 3       .entrypoint
 4       .maxstack   4
 5       .locals   init  (
 6          [ 0 int32  a,
 7          [ 1 int32  b)
 8       L_0000:   nop  
 9       L_0001:   ldc.i4.2  
10       L_0002:   stloc.0  
11       L_0003:   ldc.i4.s   9
12       L_0005:   stloc.1  
13       L_0006:   ldloc.0  
14       L_0007:   ldloc.1  
15       L_0008:   ldloc.0  
16       L_0009:   ldloc.1  
17       L_000a:   xor  
18       L_000b:   dup  
19       L_000c:   stloc.0  
20       L_000d:   xor  
21       L_000e:   dup  
22       L_000f:   stloc.1  
23       L_0010:   xor  
24       L_0011:   stloc.0  
25       L_0012:   nop  
26       L_0013:   nop  
27       L_0014:   ret  
28  }
29 
30 

我将逐语句的说明实际的执行效果。

 

Evaluation Stack

L_0001: ldc.i4.2

 

Call  Stack

2

 

 

 

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

 

2

 

 

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

9

2

 

 

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

 

2

 

9

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

2

2

 

9

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

9

2

2

9

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

9

2

2

9

9

 

2

 

 

Evaluation Stack

 

 

Call  Stack

11

2

9

9

2

 

 

 

 

Evaluation Stack

 

 

Call  Stack

11

2

11

9

9

 

2

 

 

Evaluation Stack

 

 

Call  Stack

11

11

9

9

2

 

 

 

 

Evaluation Stack

 

 

Call  Stack

2

11

2

9

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

2

11

2

9

2

 

 

 

 

Evaluation Stack

 

 

Call  Stack

2

11

2

2

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

0

11

 

2

 

 

 

 

 

Evaluation Stack

 

 

Call  Stack

 

0

 

2

 

 

 

 

 

其对应的汇编码是:

 

 1    93 :          int  a =  2 ;
 2  00000030    mov          dword ptr [ebp-40h], 2  
 3       94 :          int  b =  9 ;
 4  00000037    mov          dword ptr [ebp-44h], 9  
 5       95 :         a ^= (b ^= (a ^= b)) ;
 6  0000003e    mov          eax,dword ptr [ebp-40h] 
 7  00000041    mov          dword ptr [ebp-48h],eax 
 8  00000044    mov          eax,dword ptr [ebp-44h] 
 9  00000047    xor          dword ptr [ebp-40h],eax 
10  0000004a    mov          eax,dword ptr [ebp-40h] 
11  0000004d    xor          dword ptr [ebp-44h],eax 
12  00000050    mov          eax,dword ptr [ebp-48h] 
13  00000053    xor          eax,dword ptr [ebp-44h] 
14  00000056    mov          dword ptr [ebp-40h],eax 

 

可以看到,a和b分别在[ebp-40h]和[ebp-44h]处,在时间xor之前先将a缓存到了[ebp-48h],然后再最后一次xor时,读的是这个缓存。

这只是在C#和.Net中的解释,在C++编译器中则是能成功交换的,汇编码如下:

 

 1  45 :      int  a =  2 ;
 2  0033180E    mov          dword ptr [a], 2  
 3       46 :      int  b =  9 ;
 4  00331815    mov          dword ptr [b], 9  
 5       47 :     a ^= (b ^= (a ^= b)) ;
 6  0033181C    mov          eax,dword ptr [a] 
 7  0033181F    xor          eax,dword ptr [b] 
 8  00331822    mov          dword ptr [a],eax 
 9  00331825    mov          ecx,dword ptr [b] 
10  00331828    xor          ecx,dword ptr [a] 
11  0033182B    mov          dword ptr [b],ecx 
12  0033182E    mov          edx,dword ptr [a] 
13  00331831    xor          edx,dword ptr [b] 
14  00331834    mov          dword ptr [a],edx 

都是直接访问的a和b 的实际位置。

 结论:不同 的语言有着不同的解释方式,有可能看着一样的代码,在不同的编译器下会产生不同的结果,你知道下面的代码结果是什么吗?

 

1  int  i = 0 ;
2  int  j = (i ++ ) + (i ++ );
3  j =?

 

希望能给大家提供一些帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值