You are comparing an unsigned int
to a signed char
. The semantics of this kind of comparison are counter-intuitive: most binary operations involving signed
and unsigned
operands are performed on unsigned operands, after converting the signed value to unsigned (if both operands have the same size after promotion). Here are the steps:
- The
signed char
value is promoted to an int
with the same value -23
.
- comparison is to be performed on
int
and unsigned int
, the common type is unsigned int
as defined in the C Standard.
- The
int
is converted to an unsigned int
with value UINT_MAX - 23
, a very large number.
- The comparison is performed on the
unsigned int
values: 23
is the smaller value, the comparison evaluates to false.
- The
else
branch is evaluated, no
is printed.
To make matters worse, if c
had been defined as a long
, the result would have depended on whether long
and int
have the same size or not. On Windows, it would print no
, whereas on 64 bit Linux, it would print yes
.
Never mix signed and unsigned values in comparisons. Enable compiler warnings to prevent this kind of mistake (-Wall
or -Weverything
). You might as well make all these warnings fatal with -Werror
to avoid this kind of ill-fated code entirely.
For a complete reference, read the following sections of the C Standard (C11) under 6.3 Conversions:
- integer promotions are explained in 6.3.1.1 Boolean, characters, and integers.
- operand conversions are detailed in 6.3.1.8 Usual arithmetic conversions.
You can download the latest draft of the C11 Standard from the working group website: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf