关于C++2005编译器的一个Bug。
大家一起确认一下我说的是否正确,也讨论一下用什么好的方法来规避这个问题。
Contact me : chuyangguang@gmail.com 褚阳光
c++ 2005编译器在使用/clr选项时在一些特殊情况下会导致Release版本程序行为失常,产生错误的结果。
以下为示例程序:(项目类型为:VC ++ 2005的 CLR控制台应用程序)
#include "stdafx.h"
using namespace System;
typedef union
{
__int16 i;
unsigned __int16 ui;
} ALLTYPE;
void func(ALLTYPE *p);
int main(array<System::String ^> ^args)
{
ALLTYPE all;
all.ui = 32769;
func(&all);
Console::WriteLine("Press Enter to exit...");
Console::ReadLine();
return 0;
}
void func(ALLTYPE *p)
{
if(p->i == 0) //如果把这两行注释掉,
Console::WriteLine("0"); //则会正常工作。
if(p->ui == 32769)
Console::WriteLine("32769"); //func的函数体必须足够长,
else if(p->ui == 32770) //否则生成Release版本时会优化为inline函数。
Console::WriteLine("32770");
else if(p->ui == 32771)
Console::WriteLine("32771");
else if(p->ui == 32772)
Console::WriteLine("32772");
else if(p->ui == 32773)
Console::WriteLine("32773");
else if(p->ui == 32774)
Console::WriteLine("32774");
else if(p->ui == 32775)
Console::WriteLine("32775");
}
生成Release版本并运行,你会发现,程序的窗口中不会显示本应该有的32769。而Debug版本是能正常显示的。
问题出在Release版本的优化上。
来看Debug版本的汇编码如下:
if(p->i == 0)
00000000 push esi
00000001 mov esi,ecx
00000003 cmp dword ptr ds:[00C22DD8h],0
0000000a je 00000011
0000000c call 78E612A9
00000011 cmp word ptr [esi],0 //判断 p->i == 0
00000015 jne 00000022
Console::WriteLine("0");
00000017 mov ecx,dword ptr ds:[023B3064h]
0000001d call 7818BFA8
if(p->ui == 32769)
00000022 cmp word ptr [esi],8001h //判断 p->ui == 0
00000027 jne 00000037
Console::WriteLine("32769");
00000029 mov ecx,dword ptr ds:[023B3068h]
0000002f call 7818BFA8
00000034 nop
00000035 jmp 000000B2
上述汇编码没有使用优化处理,老老实实用 cmp word ptr操作,运行结果正常。
再看Release版本的汇编码:
if(p->i == 0)
00000000 push edi
00000001 push esi
00000002 mov edi,ecx
00000004 cmp dword ptr ds:[009E2DD8h],0
0000000b je 00000012
0000000d call 790A39D9
00000012 xor esi,esi
00000014 cmp word ptr [edi],0 //判断 p->i == 0
00000018 jne 00000025
Console::WriteLine("0");
0000001a mov ecx,dword ptr ds:[02193058h]
00000020 call 783CE6D8
if(p->ui == 32769)
00000025 movsx eax,word ptr [edi] //问题在这里,movsx指令
00000028 mov esi,eax //优化处理,把p->ui装入esi寄存器
0000002a cmp esi,8001h //比较结果为不相等!
00000030 jne 00000043
Console::WriteLine("32769");
00000032 mov ecx,dword ptr ds:[0219305Ch]
00000038 call 783CE6D8
0000003d nop
0000003e jmp 000000C4
else if(p->ui == 32770)
00000043 cmp esi,8002h //优化后,后续比较直接使用esi寄存器的值
00000049 jne 00000059
Console::WriteLine("32770");
0000004b mov ecx,dword ptr ds:[02193060h]