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;
}
The output of debug mode, which is as expected:
i: 0, result = 0
i: 1, result = 16
(...)
i:14, result = 224
i:15, result = 240
i:16, result = 255
The output of release mode, where i:15 result is not correct:
i: 0, result = 0
i: 1, result = 16
(...)
i:14, result = 224
i:15, result = 255
i:16, result = 255
By choosing "Optimization -> Not to optimize" in Visual Studio under release mode, the output result will be correct. However I would like to know why the optimization process could lead to erroneous output.
Update:
As suggested by Mohit JainBy, prints by:
printf("i:%2d, result = %3d, i*16=%d\n", i, result, i*16) ;
The release mode output is correct:
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
This is interesting, at least from a historical perspective. I can reproduce the problem with VC 2008 (15.00.30729.01) and VC 2010 (16.00.40219.01) (targeting either 32-bit x86 or 64-bit x64). The problem doesn't occur with any of the compilers I have tried starting with VC 2012 (17.00.61030).
The command I used to compile: cl /Ox vc15-bug.cpp /FAsc
Since VC 2008 (and 2010) is rather old and the fix has been in for several years now, I don't think you can expect any action from Microsoft except to use a newer compiler (though maybe someone can suggest a workaround).
The problem is that the test to determine if the value should be forced to 255
is done based on the loop count rather than the actual result of the i * 16
expression. And the compiler simply gets the count wrong for when it should start forcing the value to 255
. I have no idea why that happens - it's just the effect that I see:
; 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 : }
Update: All versions of VC I have installed earlier than VC 2008 have the same bug, except VC6 - compiling the program crashes the VC6 compiler:
vc15-bug.cpp(10) : fatal error C1001: INTERNAL COMPILER ERROR
So this is a bug that lasted in MSVC in one form or another for more than 10 years!