﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-NetRoc's Blog-文章分类-编译器</title><link>http://www.cnitblog.com/cc682/category/7186.html</link><description>N-Tech</description><language>zh-cn</language><lastBuildDate>Tue, 27 Sep 2011 12:17:34 GMT</lastBuildDate><pubDate>Tue, 27 Sep 2011 12:17:34 GMT</pubDate><ttl>60</ttl><item><title>VC6编译器优化的一个错误</title><link>http://www.cnitblog.com/cc682/articles/43257.html</link><dc:creator>NetRoc</dc:creator><author>NetRoc</author><pubDate>Sun, 04 May 2008 06:53:00 GMT</pubDate><guid>http://www.cnitblog.com/cc682/articles/43257.html</guid><wfw:comment>http://www.cnitblog.com/cc682/comments/43257.html</wfw:comment><comments>http://www.cnitblog.com/cc682/articles/43257.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/cc682/comments/commentRss/43257.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/cc682/services/trackbacks/43257.html</trackback:ping><description><![CDATA[&nbsp;
<p align=center><span>cc682/NetRoc</span></p>
<p><span>帮朋友调试了一个很奇怪的</span><span>BUG</span><span>，呵呵。稍微记录一下，再次提醒自己编译器是不可靠的。</span></p>
<p><span>代码类似这样：</span></p>
<p><span>DWORD dwSub0, dwSub1;</span></p>
<p><span>dwSub0 = dwSub1 = 0;</span></p>
<p><span>DWORD dwLoop1 = 0, dwLoop2 = 0;</span></p>
<p><span>for (dwLoop1 =0; dwLoop1 &lt;7; ++ dwLoop1)</span></p>
<p><span>{</span></p>
<p><span>++dwSub0;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>for (dwLoop2 =0; dwLoop2 &lt;7; ++ dwLoop2)</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>++dwSub1;</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//Do something</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></p>
<p><span>}</span></p>
<p><span>Debug</span><span>情况下一切正常，执行完循环之后，</span><span>dwSub0=7,deSub1=49</span><span>。但是</span><span>Release</span><span>情况下，</span><span>dwSub0</span><span>和</span><span>dwSub1</span><span>的值都是</span><span>7</span><span>。</span></p>
<p><span>VC6</span><span>编译器在特定情况下，优化的结果变为：</span></p>
<p><span>dwLoop1</span><span>和</span><span>dwLoop2</span><span>都被初始化为</span><span>0xFFFFFFA0</span><span>，每次循环加上</span><span>0x20</span><span>，并且和</span><span>0x80</span><span>比较，用</span><span>jb</span><span>跳转。</span></p>
<p><span>最后跳转的地方汇编代码像这样：</span></p>
<p><span>eax, [esp+10h]<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>;[esp+10h]</span><span>是</span><span>dwLoop2</span></p>
<p><span>add<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>edi, 328h<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></p>
<p><span>add<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>eax, 20h</span></p>
<p><span>cmp<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>eax, 80h</span></p>
<p><span>mov<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>[esp+10h], eax</span></p>
<p><span>jb<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>loc_54E19B<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>; ++dwSub1;</span><span>问题来了！！！</span></p>
<p><span>mov<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>ecx, [esp+1Ch]<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>;[esp+1Ch]</span><span>是</span><span>dwLoop1</span></p>
<p><span>add<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>ecx, 20h</span></p>
<p><span>cmp<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>edi, offset 00EFD564h</span></p>
<p><span>mov<span>&nbsp;&nbsp;&nbsp;&nbsp; </span>[esp+1Ch], ecx</span></p>
<p><span>jl<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>loc_54E187<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>; ++dwSub0;</span></p>
<p><span>因为是要循环</span><span>7</span><span>次，编译器把</span><span>dwLoop2</span><span>初始化为</span><span>-60</span><span>，每次加</span><span>0x20</span><span>，和</span><span>0x80</span><span>比较，正好是循环</span><span>7</span><span>次。这样估计是为了在接下来的代码里面重用</span><span>dwLoop1</span><span>和</span><span>dwLoop2</span><span>。不过使用</span><span>JB</span><span>指令来做跳转就发生错误了。由于</span><span>JB</span><span>指令只判断</span><span>CF</span><span>是否为</span><span>1</span><span>，是作无符号比较，所以这里产生了错误，内层循环每次都只会执行一次就退出到外层循环了。而正确的情况应该使用有符号的</span><span>jl</span><span>。</span></p>
<p><span>至此，问题暂时算是明了了。可能是在某些极特殊的情况下，</span><span>VC</span><span>的优化策略有些</span><span>BUG</span><span>。而且据朋友说在</span><span>VC2003</span><span>下面编译也有同样的错误，就是说可能在</span><span>2003</span><span>及以前的</span><span>VC</span><span>编译器中存在同样一个错误。</span><span>2005</span><span>之后的就不能确定了。</span></p>
<p><span>通过</span><span>#pragma optimize(&#8220;&#8221;,off)</span><span>、</span><span>#pragma optimize(&#8220;&#8221;,on)</span><span>关闭这个函数的优化之后，问题解决。</span></p>
<p><span>这个问题再次向我们提醒了一件事情，编译器也并不总是可靠的，往往我们在面对一些奇怪的无法解释的</span><span>BUG</span><span>的时候，不妨回过头来考虑是否是其他原因导致的，包括编译器、硬件、执行的软件环境，等等。</span></p>
<img src ="http://www.cnitblog.com/cc682/aggbug/43257.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/cc682/" target="_blank">NetRoc</a> 2008-05-04 14:53 <a href="http://www.cnitblog.com/cc682/articles/43257.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>