Your i < c
comparison has operands of two different types, so the operand with the smaller type (lower rank) is converted to the type of the other. In this case, as -23
cannot be represented as an unsigned int
, and following the "usual arithmetic conversions," it will end up with a value considerably greater than +23
(actually, UINT_MAX + 1 - 23
), according to Paragraph #2 in the following excerpt from this (Draft) C11 Standard:
6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
2 Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or subtracting one more than the maximum value that
can be represented in the new type until the value is in the range of
the new type.
3 Otherwise, the new type is signed and the
value cannot be represented in it; either the result is
implementation-defined or an implementation-defined signal is
raised.
You can see this conversion in action by assigning c
to a separate unsigned int
and printing its value, as in the following code. Assuming a 32-bit unsigned int
, you will likely see a value of 4294967273
(which is, indeed, greater than 23
).
#include <stdio.h>
int main()
{
unsigned int i = 23;
signed char c = -23;
unsigned int uc = c; // Add a diagnostic line ...
printf("%u\n", uc); // ... and show the value being used in the comparison
if (i < c) {
printf("TRUE");
}
return 0;
}
Note: The relative size of the two variables (i
and c
) here is something of a red herring; even if you declare c
as signed int c = -23;
, you will still get the same result, due to the Usual Arithmetic Conversions (link courtesy of Jonathan Leffler's comment) – note that a signed int
cannot represent all possible values of an unsigned int
, so the very last of the 'hollow' bullets will come into play.