912M0FR34K
912M0FR34K

Reputation: 121

Why is comparing a signed char and unsigned int not working right?

I wrote this small piece of code to test something:

#include <stdio.h>

int main()
{
    unsigned  x = 1;
    signed char y = -1 ;
    if (x>y)
        printf("X > Y");
    else
        printf("X <= Y");
    return 0;
}

The output I got was "X <= Y". Isn't 1 > -1?

Upvotes: 1

Views: 1697

Answers (3)

ouah
ouah

Reputation: 145899

We have:

unsigned  x = 1;
signed char y = -1;

this expression:

x > y

is used as the controlling expression of the if statement.

After usual arithmetic conversions the right operand y will be converted to an unsigned int value. The result of the conversion of the negative signed char value -1 will be a huge unsigned int value (equal to UINT_MAX).

So the expression x > y will be evaluated as:

1U > UINT_MAX

which is always false (i.e., evaluated to 0).

This is the short version. To explain how do we come to this result with the C standard rules, I explain it below.

Here is how it goes:

The > relational operator is used, here it was C says on the relational operators:

Relational operators (C99, 6.5.8p3) "If both of the operands have arithmetic type, the usual arithmetic conversions are performed."

Ok, in our example both operand are of integer types and integer types are of arithmetic types. So usual arithmetic conversion will be done. What are the usual arithmetic conversions?

Usual arithmetic conversions (C99, 6.3.1.8p1) "Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:`

Ok, first integer promotions is done on each operand. How are the integer promotions performed?

Integer promotions (C99, 6.3.1.1p2) "if an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions."

y is of signed char type so it is first promoted to int after integer promotions and x is of unsigned int type and stays an unsigned int.

Then usual arithmetic conversions will find a common type between both operands. In our case, it means this:

Usual arithmetic conversions (suite) (C99, 6.3.1.8p1) "Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type."

unsigned int has the same conversion rank as the int type (remember signed char was promoted to int), so the promoted y will be converted from int (after promotion) to unsigned int. For information, integer conversion ranks are defined in (C99, 6.3.1.1p1). As you can notice, unsigned int wins over int in usual arithmetic conversions, another way of saying this is to say that unsigned is sticky.

Now how is an int value of -1 (the signed char -1 after its promotion to int) converted to an unsigned int value?`. Here is what C says on integer conversion in this specific case:

Integer conversions (C99, 6.3.1.3p2) "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."

This paragraph is written so its meaning remains independent of the signed number representation. For two's complement representation, it means the int value -1 is converted to (UINT_MAX + 1) - 1, which is equal to UINT_MAX. So in our specific case,

x > y

is equivalent to

1U > UINT_MAX

is equivalent to

0

Upvotes: 10

Alnitak
Alnitak

Reputation: 339985

If you compare variables that aren't the same type, one of them has to be coerced into the type of the other before the comparison is done.

"Shorter" types will get promoted into "longer" types.

In this case signed char y will have been converted into the unsigned int with value UINT_MAX.

Specifically, assuming a compiler that uses 32-bit ints:

   signed char          -1 = 0xff        becomes
-> signed int           -1 = 0xffffffff  becomes
-> unsigned int 0xffffffff = UINT_MAX

Hence x < y.

Upvotes: 7

Bo Persson
Bo Persson

Reputation: 92371

Isn't 1 > -1?

It is, unless you use unsigned values. In the world of unsigned, the smallest values are zero and one. Everything else is larger, and the language explicitly states that unsigned(-1) is the largest unsigned value.

Upvotes: 1

Related Questions