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

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

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

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

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

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

1  int  a  =   2 ;
2  int  b  =   9 ;
3  a  ^=  (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 =?

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

你真的了解a ^= (b ^= (a ^= b))吗?相关推荐

  1. 系统架构升级要不要上微服务?历“久”弥新微服务——你真的需要升级微服务架构吗

    在 <微服务架构设计模式> 一书中,作者总结了关于微服务的一些"重点",原文如下: 中国企业和开发者对微服务架构的热情让我印象深刻.但如同我给所有客户的忠告一样,我想对 ...

  2. 制作欧比旺·克诺比逼真的CG角色学习教程

    艺术站-制作欧比旺·克诺比逼真的Cg角色 大小解压后:4.98G 含课程素材文件 1920X1080 .mp4 语言:英语+中英文字幕(根据原英文字幕机译更准确) 课程获取:制作欧比旺·克诺比逼真的C ...

  3. SQL Server中SELECT会真的阻塞SELECT吗?

    在SQL Server中,我们知道一个SELECT语句执行过程中只会申请一些意向共享锁(IS) 与共享锁(S), 例如我使用SQL Profile跟踪会话86执行SELECT * FROM dbo.T ...

  4. android 手机推荐,2018年安卓机皇推荐,这几款是真的不错

    原标题:2018年安卓机皇推荐,这几款是真的不错 不知不觉,2018年悄然过去大半,今年的手机市场发展情况可以用日新月异来描述了.回看前半年,安卓手机市场风起云涌,不断涌现出口碑和质量俱佳新产品. O ...

  5. 按下enter键在各个文本框中切换焦点_你真的了解Enter键吗?请先学习本文后再回答...

    回车键Enter,应该是工作办公和娱乐中应用最多的键了,但是你真的了解吗? 一.回车键Enter:粘贴数据. 目的:粘贴复制的数据. 方法: 1.选定目标单元格并复制数据. 2.在目标单元格按Ente ...

  6. 打牌软件可以控制吗_使用crm软件真的可以帮助企业省钱吗

    使用crm软件真的可以帮助企业省钱吗 大多数企业管理者认为:"客户关系系统有什么用?真的可以帮助企业发展吗?自己做一套excel版本不就行了"其实,不以为然,当我们去寻找用户时或者 ...

  7. 基于web创建逼真的3D图形 | CSS技巧

    在成为一名web开发者之前,我从事于视觉设计行业,创造屡获殊荣,电影和电视节目等高端3D效果,例如 Tron, The Thing, Resident Evil,和 Vikings .为了能够创造这些 ...

  8. [经验]无线鼠标和无线键盘真的不能用了?——雷柏的重生之路~

    逆天大二的时候托朋友买了个雷柏的无线键盘鼠标: 用了很多年,不仅外观好而且键盘鼠标本身也很好用,可前些日子就光荣牺牲了.... 逆天百思不得其"姐",试着把电池换了,发现还是不行, ...

  9. 这次真的是下定决心了

    这次我想是真的,真的. 上上周买了一本书 数据结构 c++版  看到这本书的重点 线性表第三节,看不下去了,由于我模板学的不怎么样,数据结构c++版大部分涉及了c++ 的模板,而且我觉得这本书上的代码 ...

  10. limbo可以运行linux,这次真的了,安卓手机可以安装 Windows 10 了

    原标题:这次真的了,安卓手机可以安装 Windows 10 了 上回雷锋哥给大家分享过「安卓可以体验 "Windows 10" 了」实际上就是一个第三方安卓桌面启动器模仿 Wind ...

最新文章

  1. unity开发入门_Unity游戏开发终极入门指南
  2. php开发以太坊无法连接到远程Geth,connect: permission denied.
  3. ASP将查询数据导出EXCEL
  4. [设计模式]8. C++与中介者模式(mediator pattern)
  5. mqtt js 中乱码_Vue.js 中的 v-cloak 指令——Vue学习之路
  6. thrift使用小记
  7. Angular JS
  8. 高德地图 map.setcenter 动画_娄底三维动画制作公司价格2020行情-立艺数字
  9. 关于视频监控线缆的常识
  10. 栈的应用 后缀表达式求值
  11. 近来很多人通过这个博文加关注,为何?
  12. Atitit 理解Monad attilax总结Atiti
  13. vue x 兼容iphone_【前端vue系列】初始化一个vue工程
  14. 下载知乎视频并在线播放
  15. 无线ac管理服务器调试方法,AC功能管理无线AP设置步骤
  16. petalinux 安装
  17. 前端接收java后端返回base64二进制流下载mp4
  18. 如何摆脱CRUD等打杂状态,从事更高价值工作
  19. (附源码)springboot社区疫苗接种管理系统 毕业设计 281442
  20. FJUT 2019暑假第三次周赛 C - 郭先生的魔法阵

热门文章

  1. 怎么传mysql数据到onenet_STM32 MQTT协议 连接中国移动OneNet服务器 上传接收数据(一)...
  2. iOS App注入SDK调试
  3. 差分进化算法python 指派问题_一类指派问题的改进矩阵解法
  4. Jetson AGX Orin 连接自定义硬件设备(pinmux + 设备树)
  5. 基于NFC的近场支付技术
  6. 一、微信小程序开发详解
  7. 在当前文件夹打开PowerShell
  8. Cocos Creator 2.1.3 正式发布
  9. Java笔试选择题 1
  10. 怎样用Java制作一个选择题