Yayın modunda, kod davranışı beklendiği gibi değil


131

Aşağıdaki kod, hata ayıklama modu ve yayın modu altında (Visual Studio 2008 kullanarak) farklı sonuçlar oluşturur: The following code generates different results under debug mode and release mode (using 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;
}

Beklendiği gibi hata ayıklama modunun çıktısı:

i: 0, result =   0
i: 1, result =  16
(...)
i:14, result = 224
i:15, result = 240
i:16, result = 255

İ: 15 sonucunun doğru olmadığı yayın modunun çıktısı:

i: 0, result =   0
i: 1, result =  16
(...)
i:14, result = 224
i:15, result = 255
i:16, result = 255

Visual Studio'da yayın modu altında "Optimizasyon -> En iyi duruma getirme" seçildiğinde, çıktı sonucu doğru olacaktır. Ancak optimizasyon sürecinin neden hatalı çıktılara yol açabileceğini bilmek istiyorum.


Güncelleme:

Mohit JainBy tarafından önerildiği gibi, yazdıran:

printf("i:%2d, result = %3d, i*16=%d\n", i, result, i*16) ;

Serbest bırakma modu çıkışı doğru:

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

15
Bu bir derleyici hatası gibi görünüyor (ve bunda oldukça önemli bir hata).
WhozCraig

1
@WhozCraig Yalnızca gönderideki çıktısını günceller i * 16ve sonuç doğrudur.
Lorris Lin

4
@juanchopanza: MS ile ilgili deneyimlerime ve VS ile ilgili hata düzeltmelerime dayanarak, onlar hakkında bilgi aldıktan sonra bu tür hataları düzeltirler, ancak bu düzeltmeleri VS'nin eski sürümlerine uygulamayın; bu nedenle, herhangi bir nedenle, VS, o zaman biri daha yeni bir sürüme yükseltme yapana kadar bu tür hatalarla sıkışıp kalır.
Kaiserludi

2
FWIW bu, yaklaşan Visual Studio 2015 ile sorunsuz çalışıyor
ismail

Yanıtlar:


115

Bu, en azından tarihsel açıdan ilginç. Sorunu VC 2008 (15.00.30729.01) ve VC 2010 (16.00.40219.01) (32-bit x86 veya 64-bit x64 hedefleyerek) ile yeniden oluşturabilirim. VC 2012'den (17.00.61030) başlayarak denediğim hiçbir derleyicide sorun oluşmuyor.

Derlemek için kullandığım komut: cl /Ox vc15-bug.cpp /FAsc

VC 2008 (ve 2010) oldukça eski olduğundan ve düzeltme birkaç yıldır uygulandığından, Microsoft'tan daha yeni bir derleyici kullanmak dışında herhangi bir işlem bekleyebileceğinizi sanmıyorum (yine de birileri bir geçici çözüm önerebilir).

Sorun, değerin zorlanıp zorlanmayacağını belirleyen testin ifadenin 255gerçek sonucu yerine döngü sayısına göre yapılmasıdır i * 16. Ve derleyici, değeri ne zaman zorlamaya başlaması gerektiğine dair sayımı yanlış anlıyor 255. Bunun neden olduğu hakkında hiçbir fikrim yok - sadece gördüğüm etki:

; 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   :        }

Güncelleme : VC 2008'den önce kurduğum tüm VC sürümlerinde aynı hata var, VC6 dışında - programı derlemek VC6 derleyicisini çökertiyor:

vc15-bug.cpp(10) : fatal error C1001: INTERNAL COMPILER ERROR

Yani bu, MSVC'de 10 yıldan fazla bir süredir bir şekilde veya başka bir şekilde devam eden bir hatadır!


Eğer x86 derleme zamanlamasına dair hafızam doğruysa, eax yerine esi ile karşılaştırmanın nedeni comp eax ise, 255 eax henüz yazıldığı için bir ardışık düzen durmasına neden olur.
Loren Pechtel

3
Tahminim (dönüşümler): sonuç> 255, sonuç / 16> 255/16, i> 15, i <= 14
teki

Çok ilginç! Dan Ayrıca karşılaştırma değiştirirseniz result > 255için result >= 255doğru davranır. VS2010 içinde değişiklikler o cmp esi, 14kadar cmp esi, 16(ve jlehiç jl).
opello

16

Bildirdiğiniz bilgilerin doğru olduğunu varsayarsak, bu bir derleyici hatası olacaktır. Derleyicinin en son sürümünü kontrol edin. Hata hala mevcutsa, bir hata raporu gönderin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.