开元周游
德国频道
查看: 1746|回复: 9
打印 上一主题 下一主题

还有++i

[复制链接]
1#
发表于 19.3.2003 02:02:48 | 只看该作者
即时机票
你们说<br><br>i=1;<br>a=++i;<br><br><br>i=1;<br>b=(++i)+(++i);<br><br>i=1;<br>c=(++i)+(++i)+(++i);<br><br>中的a,b,c分别等于多少?
2#
发表于 19.3.2003 10:27:05 | 只看该作者
a=2,b=5,c=9<br>但在c/c++中这取决于编译器.
3#
 楼主| 发表于 19.3.2003 11:36:14 | 只看该作者
但在c/c++中这取决于编译器.   <!--emo&(y)--><img src='http://bbs.kaiyuan.info/html/emoticons/thumbs_up.gif' border='0' style='vertical-align:middle' alt='thumbs_up.gif'><!--endemo--><br><br><br>Java给出的结果是2,5,9!<br><br>而各种C/C++ Complier给出的结果就大不相同了:<br><br>gcc 3.2 : 2, 6, 10<br>MSVC : 2, 6, 10;<br>g++ : 2, 7, 9;<br><br>
4#
 楼主| 发表于 19.3.2003 11:36:21 | 只看该作者
发信人: tihs (革命无罪造反有理), 信区: Programming                              <br>标  题: 说了半天大家也没有回答人家问题                                          <br>发信站: The unknown SPACE (Wed Feb 12 18:56:32 2003), 转信   <br><br>都知道(++i)+(++i)有不同实现,可为什么有的编译器会出现结果为6?<br>扯到编程风格上,一点意思都没有。这是探讨编译器实现的一个好例子。<br> <br>其实解释一点也不难。<br> <br>int add (){<br>        int i=1;<br>        int c;<br>        c=(++i)+(++i);<br>}<br> <br> <br>在gcc 3.2上(gcc version 3.2 20020903 (Red Hat Linux 8.0 3.2-7))结果<br>为6,和MSVC一样。为什么?<br> <br>下面是反汇编的结果:<br> <br>test.o:     file format elf32-i386<br><br><br> <br>Disassembly of section .text:<br> <br>00000000 &lt;add&gt;:<br>   0:   55                      push   %ebp<br>   1:   89 e5                   mov    %esp,%ebp<br>   3:   83 ec 08                sub    $0x8,%esp<br>   6:   c7 45 fc 01 00 00 00    movl   $0x1,0xfffffffc(%ebp)<br>   d:   8d 45 fc                lea    0xfffffffc(%ebp),%eax<br>  10:   ff 00                   incl   (%eax)<br>  12:   8d 45 fc                lea    0xfffffffc(%ebp),%eax<br>  15:   ff 00                   incl   (%eax)<br>  17:   8b 45 fc                mov    0xfffffffc(%ebp),%eax<br>  1a:   03 45 fc                add    0xfffffffc(%ebp),%eax<br>  1d:   89 45 f8                mov    %eax,0xfffffff8(%ebp)<br>  20:   c9                      leave<br>  21:   c3                      ret<br> <br> <br>看看17和1a,就明白了。实际上是(++i)+(++i)中,都是在i变成3后,<br>在3+3。<br>这个程序等价于<br><br><br> <br>int i=1;<br>int j, tmp;<br>++i;<br>++i;<br>tmp = i;<br>j = i+tmp;<br> <br>在gcc里。(++i)+(++i)+(++i)也为10。下面是代码:<br> <br>00000000 &lt;add&gt;:<br>   0:   55                      push   %ebp<br>   1:   89 e5                   mov    %esp,%ebp<br>   3:   83 ec 08                sub    $0x8,%esp<br>   6:   c7 45 fc 01 00 00 00    movl   $0x1,0xfffffffc(%ebp)<br>   d:   c7 45 f8 00 00 00 00    movl   $0x0,0xfffffff8(%ebp)<br>  14:   8d 45 fc                lea    0xfffffffc(%ebp),%eax<br>  17:   ff 00                   incl   (%eax)<br>  19:   8d 45 fc                lea    0xfffffffc(%ebp),%eax<br>  1c:   ff 00                   incl   (%eax)<br>  1e:   8b 45 fc                mov    0xfffffffc(%ebp),%eax<br>  21:   8b 55 fc                mov    0xfffffffc(%ebp),%edx<br><br><br>  24:   01 c2                   add    %eax,%edx<br>  26:   8d 45 fc                lea    0xfffffffc(%ebp),%eax<br>  29:   ff 00                   incl   (%eax)<br>  2b:   89 d0                   mov    %edx,%eax<br>  2d:   03 45 fc                add    0xfffffffc(%ebp),%eax<br>  30:   89 45 f8                mov    %eax,0xfffffff8(%ebp)<br>  33:   c9                      leave<br>  34:   c3                      ret<br> <br> <br>也就是说,它的实现是(i+1)===&gt;i, (i+1)===&gt;i,这时候i=3,两个i相加,<br>得6.然后再来一次(i+1)===&gt;i,此时i=4,加上原来的6,结果就是10.<br> <br>这个程序等价于<br> <br>int i=1;<br>int j, tmp1, tmp2;<br>++i;<br>++i;<br>tmp1 = i;<br>tmp2 = i;<br>tmp2 = tmp1 + tmp2;<br><br><br>j = tmp2+i;
5#
 楼主| 发表于 19.3.2003 11:39:07 | 只看该作者
总结: <span style='font-size:30pt;line-height:100%'>转</span><br><br>发信人: thrust (小猪哼哼*减肥中), 信区: Programming                             <br>标  题: 总结修订版                                                              <br>发信站: The unknown SPACE (Fri Feb 14 15:13:58 2003), 转信  <br> <br>看看也差不多了, 牛鬼蛇神们也都出来了. 俺总结两句, 大家觉得不对可以指出来.<br>我手头没有C的标准, 是按照C++的来写的, 我想大概对C也好用. 如果不是, 请告<br>诉我.<br> <br>C/C++语言的表达式计算顺序由好几个因素决定. 第一个, 最明显的, 如果A运算<br>的操作数是B运算的结果, 那么肯定B要比A先算. 比如a+b*c, 那肯定先做乘法.<br>第二个, 一个表达式中可能有一个到多个sequence point. 翻译一下, 就是说,<br>规定所有应该在point之前的运算,必须在所有point之后的运算之前完成. 至于<br>point之前的这些运算中哪个先做, 哪个后做, 是没有规定的. 其余的项目未作<br>规定, 如果产生二义性, 那说明你的表达式不合理. 这里我说的不合理, 意思是<br>标准未经定义的行为, 编译器可以根据自己的需要进行解释, 倒不一定会产生编<br>译错误.<br>比如说, 下面的表达式是不合理的:<br>a=(++i)*(i+1);<br>// 中间的乘法肯定要最后做. 但是左右两边先算哪个? 先算++i, 那么式子<br>// 变成(i+1)*(i+2), i++, 先算i+1, 那么式子变成(i+1)*(i+1), i++,<br>// 有二义性.<br>*++b=*b*2;<br><br><br>// 中间的赋值是最后做, 但是左右先算哪个? 不知道.<br> <br>有一点要注意: 括号并不代表先被计算. 比如,<br>a=(++i)+i;<br>// 是一个不合理的式子. 并不是说, ++i外面有括号, 就会被先计算了;<br>// 事实上, C++标准根本就没有规定precedence, 完全是用语法来规定的.<br>// 而(++i)和i同为primary expression, 它们两个哪个先算是没规定的.<br> <br>按照规定, sequence point 有这么几类:<br>第一, 表达式运算完成是一个sequence point.<br>第二, 函数调用之前, 所有的参数计算完毕, 是一个sequence point.<br>第三, 函数返回值被copy之后, 是一个sequence point.<br>第四, a&&b, a||b, a?b:c, a,b四种运算符: 在a算完之后是一个sequence point.<br> <br>解释一下. 第一条没什么好说的. 第二条, 函数的参数计算完后才开始执行函数.<br>第三条, 函数的返回值copy完以后, 才开始算其它的部分. 把二和三合起来看,<br>一个函数的执行和其返回值的copy是一个整体, 中间不插入对表达式其它部分的<br>计算. 这里的函数是广义的, 包括操作符重载, inline function, 隐式的类型转<br>换函数等等. 第四条, 说明第一个操作数总是比其它的要先计算.<br> <br>另一条很重要的规定: 在两个sequence point之间, 一个标量最多只能被修改一次.<br>如果修改一次以上, 则其结果未定义. 因此如下的表达式都是不合理的:<br><br><br>a=(++i)+(++i);<br>// 这个表达式只有最后一个sequence point, 因此修改两次i是不合理的.<br>i+=++i;<br>// 同上面一样. ++i和i+=...修改了两次i.<br>而以下的表达式是合理的:<br>a=(++i)==(++j);<br>// i和j各被修改了一次.<br>a=(++i) && (++i);<br>// 这个式子中间有一个sequence point: 在算完第一个++i之后. 因此, 这个<br>// 表达式被分成了两段, 每段修改了一次i, 是允许的.<br>a=(++i==++j) && (++i==++j);<br>// 同上.<br> <br>牵涉到函数调用是一样的道理. 比如说:<br>cout&lt;&lt;++a&lt;&lt;++a;<br>// 其实是翻译成:<br>operator&lt;&lt; (operator&lt;&lt; (cout,++a),++a);<br>// 这是个不合理的式子. 函数调用的参数计算顺序是未作规定的; 外层函数调用,<br>// 可以先计算第一个参数, 又是一个函数调用, 使a+1并遇上两个sequence point;<br>// 再算第二个参数, a++并再遇上两个sequence point, 这里没有问题.<br>// 但是如果先计算第二个参数, 那么a++, 然后计算第一个参数, 发现函数调用,<br>// 分别计算里层的参数, a又加一, 其值改变了两次, 这结果就是未定义的.<br><br><br>修订:<br>我见过很多教科书上说前缀++和后缀++的区别: 前缀++在整个表达式计算前<br>先加, 后缀++在整个表达式计算后再加. 其实这是片面的. 前后缀的区别仅仅在于,<br>(++i)的结果是i+1,而(i++)的结果是i. (当然最后i都被加了1, 但那只是side effect.)<br>并不存在前缀是在整个表达式之前计算, 后缀是在表达式之后计算的说法, 编<br>译器可以在满足sequence point 限制的条件下, 自由地选择+1的时间.<br>自减运算--也是类似的.<br>另一个区别是, 前缀++/--的结果是个lvalue, 而后缀的结果是rvalue.<br>事实上, ++i和i+=1是等价的.
6#
发表于 19.3.2003 11:59:10 | 只看该作者
7#
 楼主| 发表于 19.3.2003 12:22:50 | 只看该作者
<!--QuoteBegin--brett+Mar 19 2003, 11:59 AM--></span><table border='0' align='center' width='95%' cellpadding='3' cellspacing='1'><tr><td><b>QUOTE</b> (brett @ Mar 19 2003, 11:59 AM)</td></tr><tr><td id='QUOTE'><!--QuoteEBegin--> 搞7捻3 <!--emo&:huh:--><img src='http://bbs.kaiyuan.info/html/emoticons/huh.gif' border='0' style='vertical-align:middle' alt='huh.gif'><!--endemo-->  <!--emo&:huh:--><img src='http://bbs.kaiyuan.info/html/emoticons/huh.gif' border='0' style='vertical-align:middle' alt='huh.gif'><!--endemo--> <!--QuoteEnd--> </td></tr></table><span class='postcolor'> <!--QuoteEEnd--><br> 什么意思?不明白! <!--emo&:huh:--><img src='http://bbs.kaiyuan.info/html/emoticons/huh.gif' border='0' style='vertical-align:middle' alt='huh.gif'><!--endemo-->  <!--emo&:huh:--><img src='http://bbs.kaiyuan.info/html/emoticons/huh.gif' border='0' style='vertical-align:middle' alt='huh.gif'><!--endemo-->  
8#
发表于 19.3.2003 12:41:41 | 只看该作者
总之,我觉得++,--这两个双目运算符都有副作用,不应在复杂的表达式中出现.
9#
发表于 19.3.2003 12:58:01 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
10#
发表于 19.3.2003 13:50:46 | 只看该作者
上海话  <!--emo&--><img src='http://bbs.kaiyuan.info/html/emoticons/laugh.gif' border='0' style='vertical-align:middle' alt='laugh.gif'><!--endemo-->  
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点信息

站点统计| 举报| Archiver| 手机版| 小黑屋

Powered by Discuz! X3.2 © 2001-2014 Comsenz Inc.

GMT+1, 26.12.2024 06:48

关于我们|Apps

() 开元网

快速回复 返回顶部 返回列表