It is a Visual Studio bug, but let's start by the aspects that are not bugs.
Section 5, Note 9 of the then applicable C++ standard first discusses what to do if the operands are of different bit widths, before proceeding what to do if they are the same but differ in the sign:
...
Otherwise, if the operand that has unsigned integer type has rank
greater than or equal to the rank of the type of the other operand,
the operand with signed integer type shall be converted to the type of
the operand with unsigned integer type.
This is where we learn that the comparison has to operate in unsigned arithmetic. We now need to learn what this means for the value -10.
Section 4.6 tells us:
If the destination type is unsigned, the resulting value is the least
unsigned integer congruent to the source integer (modulo 2 n where n
is the number of bits used to represent the unsigned type). [Note: In
a two’s complement representation, this conversion is conceptual and
there is no change in the bit pattern (if there is no truncation). —
end note ] 3 If the destination type is signed, the value is unchanged
if it can be represented in the destination type (and bit-field width);
otherwise, the value is implementation-defined.
As you can see, a specific pretty high value (4294967286, or 0xFFFFFFF6, assuming unsigned int
is a 32-bit number) is being compared with 10, and so the standard guarantees that printf
is really never called.
Now you can believe me that there is no rule in the standard requiring a diagnostic in this case, so the compiler is free not to issue any. (Indeed, some people write -1
with the intention of producing an all-ones bit pattern. Others use int
for iterating arrays, which results in signed/unsigned comparisons between size_t
and int
. Ugly, but guaranteed to compile.)
Now Visual Studio issues some warnings "voluntarily".
This results in a warning already under default settings (level 3):
int a = -10;
unsigned int b = 10;
if( a < b ) // C4018
{
printf( "Error in line above: this will not be printed\n" );
}
The following requires /W4
to get a warning. Notice that the warning was reclassified. It changed from a warning C4018 to a warning C4245. This is apparently by design. A logic error that breaks a comparison nearly always is less dangerous than one that appears to work with positive-positive comparisons but breaks down with positive-negative ones.
const int a = -10;
unsigned int b = 10;
if( a < b ) // C4245
{
printf( "Error in line above: this will not be printed\n" );
}
But your case was yet different:
int a = -10;
const unsigned int b = 10;
if( a < b ) // no warning
{
printf( "Error in line above: this will not be printed\n" );
}
And there is no warning whatsoever. (Well, you should retry with -Wall
if you want to be sure.) This is a bug. Microsoft says about it:
Thank you for submitting this feedback. This is a scenario where we
should emit a C4018 warning. Unfortunately, this particular issue is
not a high enough priority to fix in the next release given the
resources that we have available.
Out of curiosity, I checked using Visual Studio 2012 SP1 and the defect is still there - no warning with -Wall
.