在发布模式下,代码行为不符合预期
In release mode, code behavior is not as expected
以下代码在debug模式和release模式下生成不同的结果
(使用 Visual Studio 2008):
int _tmain(int argc, _TCHAR* argv[])
{
for( int i = 0; i < 17; i++ )
{
int result = i * 16;
if( result > 255 )
{
result = 255;
}
printf("i:%2d, result = %3d\n", i, result) ;
}
return 0;
}
调试模式的输出,符合预期:
i: 0, result = 0
i: 1, result = 16
(...)
i:14, result = 224
i:15, result = 240
i:16, result = 255
释放模式的输出,其中i:15结果不正确:
i: 0, result = 0
i: 1, result = 16
(...)
i:14, result = 224
i:15, result = 255
i:16, result = 255
release模式下Visual Studio中选择"Optimization -> Not to optimize",输出结果是正确的。但是我想知道为什么优化过程会导致错误的输出。
更新:
根据 Mohit JainBy 的建议,印刷者:
printf("i:%2d, result = %3d, i*16=%d\n", i, result, i*16) ;
释放模式输出正确:
i: 0, result = 0, i*16=0
i: 1, result = 16, i*16=16
(...)
i:14, result = 224, i*16=224
i:15, result = 240, i*16=240
i:16, result = 255, i*16=256
假设您报告的事实是正确的,这将是一个编译器错误。检查最新版本的编译器。如果错误仍然存在,请提交错误报告。
这很有趣,至少从历史的角度来看是这样。我可以用 VC 2008 (15.00.30729.01) and VC 2010 (16.00.40219.01) (针对 32 位 x86 或 64 位 x64)。我尝试从 VC 2012 (17.00.61030).
开始的任何编译器都没有出现该问题
我编译时使用的命令:cl /Ox vc15-bug.cpp /FAsc
由于 VC 2008(和 2010)相当陈旧并且修复已经存在好几年了,我认为你不能指望微软采取任何行动,除非使用更新的编译器(尽管也许有人可以建议解决方法)。
问题在于,确定值是否应强制为 255
的测试是根据循环计数而不是 i * 16
表达式的实际结果完成的。并且编译器在应该开始将值强制为 255
的时间上简单地得到了错误的计数。我不知道为什么会这样——这就是我看到的效果:
; 6 : for( int i = 0; i < 17; i++ )
00001 33 f6 xor esi, esi
$LL4@main:
00003 8b c6 mov eax, esi
00005 c1 e0 04 shl eax, 4
; 7 : {
; 8 : int result = i * 16;
; 9 :
; 10 : if( result > 255 )
// the value `esi` is compared with in the following line should be 15!
00008 83 fe 0e cmp esi, 14 ; 0000000eH
0000b 7e 05 jle SHORT $LN1@main
; 11 : {
; 12 : result = 255;
0000d b8 ff 00 00 00 mov eax, 255 ; 000000ffH
$LN1@main:
; 13 : }
更新:我安装的VC 2008之前的所有VC版本都有相同的错误,除了VC6 - 编译该程序使 VC6 编译器崩溃:
vc15-bug.cpp(10) : fatal error C1001: INTERNAL COMPILER ERROR
所以这是一个以某种形式在 MSVC 中持续了 10 多年的错误!
以下代码在debug模式和release模式下生成不同的结果 (使用 Visual Studio 2008):
int _tmain(int argc, _TCHAR* argv[])
{
for( int i = 0; i < 17; i++ )
{
int result = i * 16;
if( result > 255 )
{
result = 255;
}
printf("i:%2d, result = %3d\n", i, result) ;
}
return 0;
}
调试模式的输出,符合预期:
i: 0, result = 0
i: 1, result = 16
(...)
i:14, result = 224
i:15, result = 240
i:16, result = 255
释放模式的输出,其中i:15结果不正确:
i: 0, result = 0
i: 1, result = 16
(...)
i:14, result = 224
i:15, result = 255
i:16, result = 255
release模式下Visual Studio中选择"Optimization -> Not to optimize",输出结果是正确的。但是我想知道为什么优化过程会导致错误的输出。
更新:
根据 Mohit JainBy 的建议,印刷者:
printf("i:%2d, result = %3d, i*16=%d\n", i, result, i*16) ;
释放模式输出正确:
i: 0, result = 0, i*16=0
i: 1, result = 16, i*16=16
(...)
i:14, result = 224, i*16=224
i:15, result = 240, i*16=240
i:16, result = 255, i*16=256
假设您报告的事实是正确的,这将是一个编译器错误。检查最新版本的编译器。如果错误仍然存在,请提交错误报告。
这很有趣,至少从历史的角度来看是这样。我可以用 VC 2008 (15.00.30729.01) and VC 2010 (16.00.40219.01) (针对 32 位 x86 或 64 位 x64)。我尝试从 VC 2012 (17.00.61030).
开始的任何编译器都没有出现该问题我编译时使用的命令:cl /Ox vc15-bug.cpp /FAsc
由于 VC 2008(和 2010)相当陈旧并且修复已经存在好几年了,我认为你不能指望微软采取任何行动,除非使用更新的编译器(尽管也许有人可以建议解决方法)。
问题在于,确定值是否应强制为 255
的测试是根据循环计数而不是 i * 16
表达式的实际结果完成的。并且编译器在应该开始将值强制为 255
的时间上简单地得到了错误的计数。我不知道为什么会这样——这就是我看到的效果:
; 6 : for( int i = 0; i < 17; i++ )
00001 33 f6 xor esi, esi
$LL4@main:
00003 8b c6 mov eax, esi
00005 c1 e0 04 shl eax, 4
; 7 : {
; 8 : int result = i * 16;
; 9 :
; 10 : if( result > 255 )
// the value `esi` is compared with in the following line should be 15!
00008 83 fe 0e cmp esi, 14 ; 0000000eH
0000b 7e 05 jle SHORT $LN1@main
; 11 : {
; 12 : result = 255;
0000d b8 ff 00 00 00 mov eax, 255 ; 000000ffH
$LN1@main:
; 13 : }
更新:我安装的VC 2008之前的所有VC版本都有相同的错误,除了VC6 - 编译该程序使 VC6 编译器崩溃:
vc15-bug.cpp(10) : fatal error C1001: INTERNAL COMPILER ERROR
所以这是一个以某种形式在 MSVC 中持续了 10 多年的错误!