En el modo release, el comportamiento del código no es el esperado


El siguiente código genera diferentes resultados en modo debug y modo release (usando 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;
}

La salida del modo de depuración, que es como se espera:

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

La salida del modo release, donde el resultado i: 15 no es correcto:

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

Al elegir "Optimización -> No optimizar" en Visual Studio en modo release, el resultado de salida será correcto. Sin embargo, me gustaría saber por qué el proceso de optimización podría conducir a errores salida.


Actualización:

Como sugiere Mohit JainBy, impresiones de:

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

La salida del modo de liberación es correcta:

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
Author: Mohit Jain, 2015-07-09

2 answers

Esto es interesante, al menos desde una perspectiva histórica. Puedo reproducir el problema con VC 2008 (15.00.30729.01) y VC 2010 (16.00.40219.01) (focalización de 32-bit x86 o x64 de 64 bits). El problema no ocurre con ninguno de los compiladores que he probado a partir de VC 2012 (17.00.61030).

El comando que utilicé para compilar: cl /Ox vc15-bug.cpp /FAsc

Desde VC 2008 (y 2010) es bastante viejo y la solución ha estado en varios años, no creo que pueda espere cualquier acción de Microsoft excepto usar un compilador más nuevo (aunque tal vez alguien pueda sugerir una solución).

El problema es que la prueba para determinar si el valor debe ser forzado a 255 se realiza en función del recuento de bucles en lugar del resultado real de la expresión i * 16. Y el compilador simplemente obtiene el conteo incorrecto para cuando debería comenzar a forzar el valor a 255. No tengo idea de por qué sucede eso - es solo el efecto que veo:

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

Actualización : Todas las versiones de VC que he instalado antes de VC 2008 tienen el mismo error, excepto VC6-compiling el programa se bloquea el compilador VC6:

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

Así que este es un error que duró en MSVC de una forma u otra por más de 10 años!

 114
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-09 07:28:28

Asumiendo que los hechos reportados son correctos, esto sería un error del compilador. Compruebe la última versión del compilador. Si el error sigue presente, envíe un informe de error.

 16
Author: David Heffernan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-09 08:51:08