|
昨天在CSDN上面看到这样一贴,居然爆料VC6/VS2003有一个严重的bug,于是自己也仔细研究一番:
1、原贴地址:
2、出错代码:
// VC6/VC2003 使用/O2编译(默认的release模式), 输出结果有"impossible!!!" #include <stdio.h> int main() { static const int T[1] = {0}; int n = 0; for(int i = 536000000; i < 536000004; ++i) { if(i < 0) { printf("impossible!!!/n"); break; } if(i >= 0 && i < 1) n += T; } printf("end/n"); getchar(); return n; }
3、原因分析
当我在使用IDE环境选择Release生成后,确实发现有上述问题
于是我修改他的代码,狼兄弟建议我先看看此时i的十进制数值与十六进制数值:
#include <stdio.h> int main() { static const int T[1] = {0}; int n = 0; for(int i = 536000000; i < 536000004; ++i) { if(i < 0) { printf("impossible is %d/t%x/n",i,i); break; } if(i >= 0 && i < 1) n += T; } printf("end/n"); return n; }
在命令行编译参数中添加/Fa即可得到汇编代码(当前目录中Hello.asm):
TITLEHello.cpp.386Pinclude listing.incif @Version gt 510.model FLATelse_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'_TEXTENDS_DATASEGMENT DWORD USE32 PUBLIC 'DATA'_DATAENDSCONSTSEGMENT DWORD USE32 PUBLIC 'CONST'CONSTENDS_BSSSEGMENT DWORD USE32 PUBLIC 'BSS'_BSSENDS_TLSSEGMENT DWORD USE32 PUBLIC 'TLS'_TLSENDS;COMDAT ??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@_DATASEGMENT DWORD USE32 PUBLIC 'DATA'_DATAENDS;COMDAT ??_C@_04NBKL@end?6?$AA@_DATASEGMENT DWORD USE32 PUBLIC 'DATA'_DATAENDS;COMDAT _main_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'_TEXTENDSFLATGROUP _DATA, CONST, _BSSASSUMECS: FLAT, DS: FLAT, SS: FLATendifCONSTSEGMENT_?T@?1??main@@9@4QBHB DD 00HCONSTENDSPUBLIC_mainPUBLIC??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@ ; `string'PUBLIC??_C@_04NBKL@end?6?$AA@; `string'EXTRN_printf:NEAR;COMDAT ??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@; File Hello.cpp_DATASEGMENT??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@ DB 'impossible is %d', 09HDB'%x', 0aH, 00H; `string'_DATAENDS;COMDAT ??_C@_04NBKL@end?6?$AA@_DATASEGMENT??_C@_04NBKL@end?6?$AA@ DB 'end', 0aH, 00H; `string'_DATAENDS;COMDAT _main_TEXTSEGMENT_mainPROC NEAR; COMDAT; File Hello.cpp; Line 4pushesi; Line 6xoresi, esi; Line 8movecx, 536000000; 1ff2b600Hmoveax, OFFSET FLAT:_?T@?1??main@@9@4QBHB+2144000000$L581:; Line 10cmpeax, OFFSET FLAT:_?T@?1??main@@9@4QBHBjlSHORT $L595; Line 15cmpeax, OFFSET FLAT:_?T@?1??main@@9@4QBHB+4jgeSHORT $L582; Line 16addesi, DWORD PTR [eax]$L582:addeax, 4incecxcmpeax, OFFSET FLAT:_?T@?1??main@@9@4QBHB+2144000016jlSHORT $L581; Line 19pushOFFSET FLAT:??_C@_04NBKL@end?6?$AA@; `string'call_printfaddesp, 4; Line 20moveax, esipopesi; Line 21ret0$L595:; Line 12pushecxpushecxpushOFFSET FLAT:??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@ ; `string'call_printfaddesp, 12; 0000000cH; Line 19pushOFFSET FLAT:??_C@_04NBKL@end?6?$AA@; `string'call_printfaddesp, 4; Line 20moveax, esipopesi; Line 21ret0_mainENDP_TEXTENDSEND
查看Release生成后在汇编代码:
00401000 push esi 00401001 xor esi,esi 00401003 mov eax,800B5514h 00401008 cmp eax,offset string L"/0" (407D14h) 0040100D jl main+24h (401024h) 0040100F cmp eax,407D18h 00401014 jge main+18h (401018h) 00401016 add esi,dword ptr [eax] 00401018 add eax,4 0040101B cmp eax,800B5524h 00401020 jl main+8 (401008h) 00401022 jmp main+31h (401031h) 00401024 push offset string "impossible!!!/n" (407104h) 00401029 call printf (4011FEh) 0040102E add esp,4 00401031 push offset string "end/n" (4070FCh) 00401036 call printf (4011FEh) 0040103B mov eax,dword ptr [__iob+4 (409044h)] 00401040 add esp,4 00401043 dec eax 00401044 mov dword ptr [__iob+4 (409044h)],eax 00401049 js main+55h (401055h) 0040104B inc dword ptr [__iob (409040h)] 00401051 mov eax,esi 00401053 pop esi 00401054 ret 00401055 push offset __iob (409040h) 0040105A call _filbuf (401066h) 0040105F add esp,4 00401062 mov eax,esi 00401064 pop esi 00401065 ret
可以惊奇的发现i <0会被优化成0x800B5514 <0x00407D14,于是乎让我想起前面编译器优化参数的三个选项,打开IDE的编译选项:
3、解决办法:
这是由于编译器参数优化造成的,具体影响结果的参数是/O2(代码速度最快),如果使用/Od(不使用优化)则不会出现上述结果,测试如下图:
在此,十分感谢寂寞的狼、iceboy等友友的耐心的指导与无私的帮助!
4、相关文章:
深入探究VC —— 编译器cl.exe(1)
深入探究VC —— 编译器cl.exe(2)
|
免责声明:
1. 本站所有资源来自网络搜集或用户上传,仅作为参考不担保其准确性!
2. 本站内容仅供学习和交流使用,版权归原作者所有!© 查看更多
3. 如有内容侵害到您,请联系我们尽快删除,邮箱:kf@codeae.com
|