web-dev-qa-db-ja.com

リリースモードでは、コードの動作は期待どおりではありません

次のコードは、デバッグモードとリリースモードで異なる結果を生成します(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

リリースモードのVisual Studioで[最適化->最適化しない]を選択すると、出力結果が正しくなります。ただし、最適化プロセスが誤った出力につながる理由を知りたいと思います。


更新:

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
131
Lorris Lin

これは、少なくとも歴史的な観点から興味深いです。 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)はかなり古く、修正は数年前から行われているため、新しいコンパイラを使用する以外にMicrosoftからのアクションを期待できないと思います(ただし、回避策を提案してください)。

問題は、値を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年以上続いたバグです!

115
Michael Burr

報告された事実が正しいと仮定すると、これはコンパイラのバグになります。コンパイラの最新バージョンを確認してください。バグがまだ存在する場合は、バグレポートを送信してください。

16
David Heffernan