NetRoc's Blog

N-Tech

 

VC6编译器优化的一个错误

 

cc682/NetRoc

帮朋友调试了一个很奇怪的BUG,呵呵。稍微记录一下,再次提醒自己编译器是不可靠的。

代码类似这样:

DWORD dwSub0, dwSub1;

dwSub0 = dwSub1 = 0;

DWORD dwLoop1 = 0, dwLoop2 = 0;

for (dwLoop1 =0; dwLoop1 <7; ++ dwLoop1)

{

++dwSub0;

         for (dwLoop2 =0; dwLoop2 <7; ++ dwLoop2)

         {

                   ++dwSub1;

                   //Do something

         }

}

Debug情况下一切正常,执行完循环之后,dwSub0=7,deSub1=49。但是Release情况下,dwSub0dwSub1的值都是7

VC6编译器在特定情况下,优化的结果变为:

dwLoop1dwLoop2都被初始化为0xFFFFFFA0,每次循环加上0x20,并且和0x80比较,用jb跳转。

最后跳转的地方汇编代码像这样:

eax, [esp+10h]       ;[esp+10h]dwLoop2

add     edi, 328h      

add     eax, 20h

cmp     eax, 80h

mov     [esp+10h], eax

jb      loc_54E19B      ; ++dwSub1;问题来了!!!

mov     ecx, [esp+1Ch]     ;[esp+1Ch]dwLoop1

add     ecx, 20h

cmp     edi, offset 00EFD564h

mov     [esp+1Ch], ecx

jl      loc_54E187      ; ++dwSub0;

因为是要循环7次,编译器把dwLoop2初始化为-60,每次加0x20,和0x80比较,正好是循环7次。这样估计是为了在接下来的代码里面重用dwLoop1dwLoop2。不过使用JB指令来做跳转就发生错误了。由于JB指令只判断CF是否为1,是作无符号比较,所以这里产生了错误,内层循环每次都只会执行一次就退出到外层循环了。而正确的情况应该使用有符号的jl

至此,问题暂时算是明了了。可能是在某些极特殊的情况下,VC的优化策略有些BUG。而且据朋友说在VC2003下面编译也有同样的错误,就是说可能在2003及以前的VC编译器中存在同样一个错误。2005之后的就不能确定了。

通过#pragma optimize(“”,off)#pragma optimize(“”,on)关闭这个函数的优化之后,问题解决。

这个问题再次向我们提醒了一件事情,编译器也并不总是可靠的,往往我们在面对一些奇怪的无法解释的BUG的时候,不妨回过头来考虑是否是其他原因导致的,包括编译器、硬件、执行的软件环境,等等。

posted on 2008-05-04 14:53 NetRoc 阅读(457) 评论(0)  编辑 收藏 引用 所属分类: 编译器

只有注册用户登录后才能发表评论。

导航

统计

常用链接

留言簿(7)

随笔档案(99)

文章分类(35)

文章档案(32)

Friends

Mirror

搜索

最新评论

阅读排行榜

评论排行榜