Im Freigabemodus ist das Codeverhalten nicht wie erwartet

Lesezeit: 3 Minuten

Benutzeravatar von Lorris Lin
Lorris Lin

Der folgende Code generiert unterschiedliche Ergebnisse im Debugmodus und im Freigabemodus (mit 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;
}

Die Ausgabe des Debug-Modus, die wie erwartet ist:

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

Die Ausgabe des Freigabemodus, bei dem das i:15-Ergebnis nicht korrekt ist:

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

Durch Auswahl von „Optimierung -> Nicht zu optimieren“ in Visual Studio im Freigabemodus ist das Ausgabeergebnis korrekt. Ich würde jedoch gerne wissen, warum der Optimierungsprozess zu einer fehlerhaften Ausgabe führen könnte.


Aktualisieren:

Wie von Mohit JainBy vorgeschlagen, Drucke von:

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

Die Ausgabe des Freigabemodus ist korrekt:

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

  • Das sieht aus wie ein Compiler-Fehler (und ein ziemlich bedeutender noch dazu).

    – WhozCraig

    9. Juli 2015 um 5:49 Uhr


  • @WhozCraig Aktualisiert nur die Ausgabe von i * 16 in der Post, und das Ergebnis ist korrekt.

    – Lorris Lin

    9. Juli 2015 um 6:17 Uhr

  • @juanchopanza: Aus meiner Erfahrung mit MS und Bugfixes für VS beheben sie solche Fehler, nachdem sie darüber informiert wurden, wenden diese Fixes jedoch nicht auf ältere Versionen von VS an, wenn man also aus irgendeinem Grund gezwungen ist, eine ältere Version von zu verwenden VS, dann bleibt man bei solchen Bugs hängen, bis man auf eine neuere Version upgraden kann.

    – Kaiserludi

    9. Juli 2015 um 11:27 Uhr

  • FWIW funktioniert gut mit dem kommenden Visual Studio 2015

    – ismail

    9. Juli 2015 um 17:58 Uhr

Benutzeravatar von Michael Burr
Michael Burr

Das ist interessant, zumindest aus historischer Perspektive. Ich kann das Problem mit VC 2008 (15.00.30729.01) reproduzieren und VC 2010 (16.00.40219.01) (für entweder 32-Bit x86 oder 64-Bit x64). Das Problem tritt bei keinem der Compiler auf, die ich ab VC 2012 (17.00.61030) ausprobiert habe.

Der Befehl, den ich zum Kompilieren verwendet habe: cl /Ox vc15-bug.cpp /FAsc

Da VC 2008 (und 2010) ziemlich alt ist und der Fix bereits seit mehreren Jahren vorhanden ist, können Sie meiner Meinung nach keine Aktion von Microsoft erwarten, außer einen neueren Compiler zu verwenden (obwohl vielleicht jemand eine Problemumgehung vorschlagen kann).

Das Problem ist, dass der Test bestimmt, ob der Wert erzwungen werden sollte 255 basiert auf der Anzahl der Schleifen und nicht auf dem tatsächlichen Ergebnis der i * 16 Ausdruck. Und der Compiler bekommt einfach die falsche Zählung, wann er anfangen sollte, den Wert zu erzwingen 255. Ich habe keine Ahnung, warum das passiert – es ist nur der Effekt, den ich sehe:

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

Aktualisieren: Alle Versionen von VC, die ich vor VC 2008 installiert habe, haben denselben Fehler, außer VC6 – das Kompilieren des Programms stürzt den VC6-Compiler ab:

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

Dies ist also ein Fehler, der in MSVC in der einen oder anderen Form mehr als 10 Jahre andauerte!

  • Wenn meine Erinnerung an das x86-Assembly-Timing richtig ist, ist der Grund für den Vergleich mit esi und nicht mit eax comp eax,255 würde einen Pipeline-Stall verursachen, da eax gerade geschrieben wurde.

    – Loren Pechtel

    10. Juli 2015 um 1:04 Uhr

  • Meine Vermutung (Transformationen): result > 255, result / 16 > 255 / 16, i > 15, i <= 14

    – Teki

    10. Juli 2015 um 3:43 Uhr


  • Sehr interessant! Auch wenn Sie den Vergleich aus ändern result > 255 zu result >= 255 es verhält sich richtig. In VS2010 ändert sich das cmp esi, 14 zu cmp esi, 16 (und die jle zu jl).

    – opello

    17. Juli 2015 um 15:08 Uhr


Benutzeravatar von David Heffernan
David Heffernan

Unter der Annahme, dass Ihre gemeldeten Fakten korrekt sind, wäre dies ein Compiler-Fehler. Überprüfen Sie die neueste Version des Compilers. Wenn der Fehler immer noch vorhanden ist, senden Sie einen Fehlerbericht.

1423300cookie-checkIm Freigabemodus ist das Codeverhalten nicht wie erwartet

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy