在发布模式下,代码行为不符合预期

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 多年的错误!