Section 6.3.1.8 , Regular Arithmetic Conversions, C99 details implicit integer conversions.
If both operands are of the same type, then no further conversion is required.
This does not mean that these are different types.
Otherwise, if both operands are integer types or both have unsigned integer types, the operand with the rank type of the smaller integer conversion is converted to the operand type with a higher rank.
This does not count as one of them is signed, the other is unsigned.
Otherwise, if the operand that has an unsigned integer type has a rank greater than or equal to the ranks of the type of another operand, then the operand with a signed integer type is converted to the operand type with an unsigned integer.
Bingo. x has a higher rank than y , so y is promoted to unsigned int . This means that it changes from -1 to UINT_MAX , significantly greater than 9.
The rest of the rules do not apply, since we found a match, but I will include them for completeness:
Otherwise, if the type of the operand with a signed integer type can represent all values โโof the type of the operand with an unsigned integer, then the operand with an unsigned integer type will be converted to the type of the operand with a signed integer type.
Otherwise, both operands are converted to an unsigned integer type corresponding to the type of the operand with a signed integer type.
The ranks related to this issue are shown below. All ranks are described in detail in C99, section 6.3.1.1 , Boolean, character, and integers, so you can refer to this for more details.
The rank of long long int must be greater than the rank of long int , which must be greater than the rank of int , which must be greater than the rank of short int , which must be greater than the rank of signed char .
The rank of char must be equal to the ranks of signed char and unsigned char .