В режиме выпуска поведение кода не так, как ожидалось

Следующий код генерирует разные результаты в режиме отладки и режиме выпуска (с использованием 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 в режиме выпуска, результат будет правильным. Однако я хотел бы знать, почему процесс оптимизации может привести к ошибочному выводу.


Update:

Как было предложено 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

Ответ 1

Это интересно, по крайней мере, с исторической точки зрения. Я могу воспроизвести проблему с VC 2008 (15.00.30729.01) и 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
[email protected]:
  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 [email protected]

; 11   :        {
; 12   :            result = 255;

  0000d b8 ff 00 00 00   mov     eax, 255       ; 000000ffH
[email protected]:

; 13   :        }

Обновление. Все версии VC, которые я установил раньше, чем VC 2008, имеют ту же ошибку, кроме VC6 - компиляция программы приводит к сбою компилятора VC6:

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

Итак, это ошибка, которая длилась в MSVC в той или иной форме более 10 лет!

Ответ 2

Предполагая, что ваши сообщенные факты верны, это будет ошибкой компилятора. Проверьте последнюю версию компилятора. Если ошибка все еще присутствует, отправьте отчет об ошибке.