CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
山寨机中的战斗机! 程序优化工程师到底对IT界有没有贡献
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  .NET技术 >  C#

JAVA社会看见的一个趣味怪问题,同样适合C#,待高手的解~~~~~

楼主hainang1234(海浪)2005-03-28 22:47:35 在 .NET技术 / C# 提问

int   i   =   0;  
  i   =   i++;  
  MessageBox.Show(i.ToString());  
   
  结果i是0。这是为什么?  
  JAVA和C#中的计算结果都是i==0,而在C++中i==1。  
  待高手解。 问题点数:50、回复次数:37Top

1 楼Sunmast(速马@Redmond, WA)回复于 2005-03-28 22:56:05 得分 0

现在我坚持认为这是C#和Java编译器的bug,嗯Top

2 楼alexzhang00(三角猫)回复于 2005-03-28 23:00:17 得分 0

这是   编译器   的规则问题,  
   
  C#   和   JAVA   的编译器   是区分   左增   和   右增的  
   
  int   i   =   0;  
  i   =   i++;  
  MessageBox.Show(i.ToString());  
  -------------------  
  int   i   =   0;  
  i   =   ++i;  
  MessageBox.Show(i.ToString());  
  Top

3 楼caicheng(菜菜)回复于 2005-03-28 23:02:28 得分 5

这和语言的编译机制有关,可参考编译原理  
  说明C++的编译是执行完整个行后对++进行运算的,故在显示时为1  
  1、执行i++表达式的到返回值0  
  2、执行i=表达式(付值),i=0  
  3、执行++,i=1  
  而C#和JAVA是以表达式为单位进行编译的,即先  
  1、执行i++表达式的到返回值0  
  2、执行++,i=1  
  3、执行i=表达式(付值),i=0  
  这是个人的理解,我认为差别就在此,在这些语言的编译器和优先级里,建议尽量避免此类问题,宁可多写几句:)Top

4 楼zhpsam109(JACKY.昊昊)回复于 2005-03-28 23:02:34 得分 5

这样的结果是对的!i++是一个表达式,把这个表达式的值赋值给了i,i++这个表达式的值是i的原值0!所以输出结果是0!c语言中就学过,表达式的值和变量的值是不一样的!Top

5 楼caicheng(菜菜)回复于 2005-03-28 23:03:59 得分 0

To:alexzhang00(三角猫)    
  C++的编译器   也是区分   左增   和   右增的啊Top

6 楼hainang1234(海浪)回复于 2005-03-28 23:28:36 得分 0

zhpsam109(孤寂无边)   :  
  你的说法我认同,但是,C++为什么不同?Top

7 楼Sunmast(速马@Redmond, WA)回复于 2005-03-28 23:47:52 得分 5

和C/C++精神相违背的C语系语言的编译器,就是有bug的编译器  
  按照C/C++的规则,i++总是执行完当前规则后在给i加一  
  故等效于i   =   i;i   +=   1;  
   
  不晓得实现C#编译器的时候咋想的Top

8 楼caicheng(菜菜)回复于 2005-03-29 00:06:57 得分 0

要知道开发C#的那个人叫以前在Borland做Delphi和JBuilder的,估计是习惯了那些思路吧,坚决拥护C++Top

9 楼ArLi2003(阿利,MSN:url@163.com)回复于 2005-03-29 00:16:40 得分 5

其实这个问题表面上很容易理解,但还有个更“鬼”的意义,就是:  
  ++   要比   =   更优先  
  那为什么还是0   呢?我们从IL   来分析:  
   
      IL_0000:     ldc.i4.0   //把0压入evaluation   stack  
      IL_0001:     stloc.0   //取自evaluation   stack顶部一个值回填到变量(已经完成i=i)  
      IL_0002:     ldloc.0   //加载  
      IL_0003:     dup   //拷贝复本到evaluation   stack  
      IL_0004:     ldc.i4.1   //压入1  
      IL_0005:     add   //相加  
      IL_0006:     stloc.0   //取值(返回值)  
      IL_0007:     stloc.0  
      IL_0008:     ldloc.0  
   
  这个小问题过去我曾经碰到过,我个人感觉不可理解,很明显.net(包括vc.net也一样的结果)   和java   一样没有严格按照U先级计算。。(C#   相关文档注明了++   是计算符里最U先的),而C   是先加后付值的,所以个人感觉是为了兼容java   的步进运行机制Top

10 楼ArLi2003(阿利,MSN:url@163.com)回复于 2005-03-29 00:19:11 得分 0

司马昭之心,牛人皆知   ~~~~Top

11 楼hainang1234(海浪)回复于 2005-03-29 19:08:53 得分 0

我认为正因为   ++   要比   =   优先执行,所以才应该是0。  
  先++,然后将(i++)的值赋给i,于是冲掉了开始的++操作。  
  但C++却又不是这个思路。先赋值,后++。Top

12 楼athossmth(athos)回复于 2005-03-29 19:22:12 得分 0

++比=优先也不说明问题,关键是,++返回多少?或者说:  
   
  int   i   =   0,   j=0;  
  j   =   i++;  
   
  i肯定是1了,j是多少?Top

13 楼kknd2005(人生有两种遗憾:一种是没得到,一种是得到了)回复于 2005-03-29 20:11:17 得分 0

这种代码,不要写就是了,我觉得是没必要讨论的  
   
  就和当年TC的"不稳定浮点错误"一样,没意思Top

14 楼zhouheng123456(授之以鱼,不如授之以渔)回复于 2005-03-29 20:41:28 得分 0

int   i   =   0;  
  i   =   i++;  
   
  如果是i   =   ++i;  
  就不是零了啊...  
  是先赋值在加...Top

15 楼zhouheng123456(授之以鱼,不如授之以渔)回复于 2005-03-29 20:45:30 得分 0

接上面的话  
   
   
  不过c++居然会是这样..  
   
  没试过...Top

16 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-03-29 20:50:47 得分 5

这个其实不是错误。  
   
  对于C++而言,它对于后置自增运算符的解释是,在语句执行完毕后自增。  
   
  所以,C++先执行i=i,最后再自增i,得到结果1。  
   
   
  对于C#而言,它对于后置自增运算符的解释是,在得到变量结果后自增。  
   
  所以,C#先得到i++的结果,然后马上自增,再进行i=i,但由于这个时候,后面的i的结果已经被获取,为0,C#并不会对其进行第二次获取值,所以i最终的结果是0。  
   
   
  而C#为什么不采取与C++同样的处理方式呢?原因应该非常简单,因为C#是编译成IL的,在IL中,并没有针对自增和自减所特别优化的指令。而C++是编译成汇编语言,发明自增和自减运算符其目的就在于优化汇编代码,使用自增的指令代替两数相加的指令可以大大的提高效率。  
   
  所以,在C#中,自增和自减运算符会被编译器解释成i   =   i   +   1或者i   =   i   +   1这样的代码。而后置的自增/自减运算符处理方式则只是简单的将i的值暂存,等到自增/自减结束后返回暂存的值。这样也简化了重载自增/自减运算符的代码,不准分前置和后置重载,后置的处理方式相对于前置总是固定的。Top

17 楼xxuu503(中国没有prison break只是因为the company不让拍)回复于 2005-03-29 21:24:49 得分 0

晕死了!  
   
  不晓得C++和C#还有这点不一样!Top

18 楼tajlolo(tajlolo)回复于 2005-03-29 21:54:49 得分 0

这个问题我的理解是这样的,i=i++在C#和JAVA中背后是分成这样的过程的:  
   
  ++优先级高,所以先执行i++  
  i++要分成两步来执行:  
  i=i+0,这里很关键:  
  i+0贮存在一个临时变量中:  
  i+0---->temp此时temp=0+0=0;  
  然后i执行i=i+1,此时i=1  
  然后再执行赋值运算i=temp  
  所以还是等于0  
   
  在c++中操作就不是一样的了,在c++中:  
  i++是通过累加寄存器来操作,他不会通过中间临时变量,然后直接返回值.  
  所以C++运行效率很高.  
   
  为什么JAVA和C#要这样设计呢?是因为便于装箱,在装箱的时候更有效率.  
   
  比如:  
  object   oj=(object)(i++)这种形式的运算,此时直接把temp的地址返给oj就是了,那么i怎么办?i然后自己执行自己的++运算,如果i不再使用,直接拉圾回收。  
   
  大家可以通过以下的代码来验证:  
  object   o=(object)(i++);  
  this.label1.Text=o.ToString();//输出为0  
  this.label2.Text=i.ToString();//输出为1  
  但是上面的过程是不是我说的那样,得通过IL来验证。  
   
  不知我理解得正确不?望MS的专家们来讲解一下.Top

19 楼tajlolo(tajlolo)回复于 2005-03-29 21:57:59 得分 0

上面的有误,由于i++是后置运算,在c#和java中,上面的i=i+0这个过程不必要的,应该是将i的值直接赋给中间变量tempTop

20 楼WillSmart(天天CODE)回复于 2005-03-29 22:32:06 得分 0

我的理解:C#、JAVA中i是一个Integer的对象,被i++重新附值为0;C++中i是一个值变量,放在内存中,i++后加所以在附值后再加。Top

21 楼deyunanhai(bocelli)回复于 2005-03-29 22:42:50 得分 0

这样结果是对的,要是i=++i的话结果就是1了Top

22 楼caicheng(菜菜)回复于 2005-03-29 23:19:00 得分 0

昏,别研究了,微软估计不会因为这个帖子更新C#的编译器的,再说这并不是错误啊,只不过是思路的问题^^适应就是了Top

23 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-03-29 23:41:29 得分 0

无错了,C++是效率至上的,所以自增和自减运算符会优化汇编代码。而且系统内定的后置的自增/自减运算符不会像C#一样先返回值然后再自增或自减,因为这样必然会生成变量的一个拷贝,从而影响性能,所以C++的后置自增/自减运算符规定在语句执行完后再执行。  
   
  换言之,C#为了简单,把后置的自增运算符定义为:  
   
  operator++   (   int   i,   int   postfix   )//注:仿照C++的规则,利用伪参数postfix来表明是后置  
  {  
      int   _i   =   i;  
      ++i;  
      return   _i;  
  }  
   
  而我们在C++中重载后置自增/自减运算符时也采取类似的方法。  
  但对于C++编译器而言,这种方案要创建一个临时的变量_i,还需要进行两次赋值,对于效率至上的C++是不可接受的。所以C++采取了不同于C#的复杂的方式。Top

24 楼ArLi2003(阿利,MSN:url@163.com)回复于 2005-03-30 00:39:41 得分 25

越说越出轨了,不是什么编译器BUG之类的,注意这个:  
   
  The   operand   of   a   postfix   increment   or   decrement   operation   must   be   an   expression   classified   as   a   variable,   a   property   access,   or   an   indexer   access.   The   result   of   the   operation   is   a   value   of   the   same   type   as   the   operand.  
   
  注意最后一句:result   of   the   operation   is   a   value   of   the   same   type   as   the   operand.  
  在MS的C#   语言规范的7.5.9   已经说明了,i++   将返回i的原值  
   
  然后再去瞧瞧VC的解释,msdn   2003的  
  ms-help://MS.MSDNQTR.2003FEB.2052/dv_vccelng4/html/ellrfcplsplspostfixincrementanddecrementoperators.htm  
   
  msdn2005的:  
  ms-help://MS.VSCC.2003/MS.MSDNQTR.2005APR.1033/vclang/html/_pluslang_C.2b2b_.Postfix_Increment_and_Decrement_Operators.htm  
   
  或者自己再写各写一个程序,去反汇编回来瞧瞧就知道了  
   
  我想楼主只是奇怪MS的动机。。。Top

25 楼tttick(秉承一贯懒散的生活方式与严谨的工作态度¢)CodinG)回复于 2005-03-30 01:39:02 得分 0

这个我早就发现了。。。觉得是编译的问题的。。Top

26 楼an_andy()回复于 2005-03-30 08:18:41 得分 0

studyTop

27 楼lango()回复于 2005-03-30 08:41:45 得分 0

顶Top

28 楼sunkangta(●●●●●)回复于 2005-03-30 08:48:06 得分 0

这个很正常啊先附值后再加的啊Top

29 楼myhero811104(人生四大想不开:改嫁、出家、自杀、做软件开发)回复于 2005-03-30 09:04:41 得分 0

进来学习Top

30 楼qozms(Alex)回复于 2005-03-30 09:11:19 得分 0

sfasTop

31 楼ccat(智拙)回复于 2005-03-30 09:45:29 得分 0

我认为把步进运算符和普通的数学运算式混在一起本身就是在捣乱,呵呵。Top

32 楼lzy(麒麟)回复于 2005-03-30 10:36:49 得分 0

alexzhang00(三角猫)   的答案是正解;  
   
  这是C#的语法规定的,如果你连“左增   和   右增”的语法都没搞清楚的话,只能说语法不清楚;  
   
  说编译器有问题的需要在语法上下点功夫;Top

33 楼zjh135(aaa)回复于 2005-03-30 10:44:06 得分 0

这是编译器决定的,   如果你能写编译器,你可以修改你认为正确的结果,如果我们不能写编译器,只有跟着别人跑了Top

34 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-03-30 11:03:51 得分 0

alexzhang00(三角猫)   的答案是正解;  
   
  这是C#的语法规定的,如果你连“左增   和   右增”的语法都没搞清楚的话,只能说语法不清楚;  
   
  说编译器有问题的需要在语法上下点功夫;  
   
   
  晕。。。。C语系的都区分前置和后置的自增自减运算符。。。。。现在在这里讨论的是对于后置自增自减运算符C++和C#处理方式的不同,C++的处理方式复杂,C#的处理方式简单,但都不是Bug,因为在他们各自的文档中是写的很清楚的。真正正确的解释应该是   tajlolo(tajlolo)   的分析。Top

35 楼WhatWhoWhere(不知如何是好)回复于 2005-03-30 11:46:54 得分 0

该说的说完了~~   按照   ++   运算符的规则,C#的比较完整Top

36 楼panda2fw2(我爱Monkey)回复于 2005-03-30 11:55:28 得分 0

尽量少写这种代码为好。Top

37 楼iheshi(小适)回复于 2005-03-30 17:52:23 得分 0

这样的结果是对的!i++是一个表达式,把这个表达式的值赋值给了i,i++这个表达式的值是i的原值0!所以输出结果是0!c语言中就学过,表达式的值和变量的值是不一样的!  
  Top

相关问题

  • 趣味数求解
  • java与c/c++
  • Java or C#
  • Java Or C++
  • Java OR C#
  • java c/s
  • 解释一下?关键字 oracle,java ,C#
  • 了解一下,做c或c++的工资是多少?java呢?
  • c>java?57:0
  • c++转java &&boost

关键词

  • .net
  • c#
  • c++
  • c/c++
  • 编译器
  • 执行
  • 语法
  • 编译
  • 代码
  • 汇编

得分解答快速导航

  • 帖主:hainang1234
  • caicheng
  • zhpsam109
  • Sunmast
  • ArLi2003
  • Ivony
  • ArLi2003

相关链接

  • CSDN .NET频道
  • .NET类图书
  • C#类图书
  • .NET类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo