JAVA社会看见的一个趣味怪问题,同样适合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




