Why doesn't the comparison between signed char and unsigned int work correctly?

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 result was "X <= Y". Not 1> -1?

+1


source to share


3 answers


We have:

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

      

this expression:

x > y

      

used as the control expression of an if statement.

After normal arithmetic conversions, the right-hand operand y

will be converted to a value unsigned int

. Converting a negative value signed char

-1

will result in a huge value unsigned int

(equal UINT_MAX

).

So the expression x > y

will evaluate as:

1U > UINT_MAX

      

which is always false (i.e. evaluates to 0).

This is the short version. To explain how we arrived at this result using standard C rules, I'll explain it below.

Here's how it's done:

The relational operator is used >

, here he is talking about relational operators:

Relational Operators (C99, 6.5.8p3) "If both operands are of arithmetic type, normal arithmetic conversions are performed."

Okay, in our example, both operands are integer types, and integer types are arithmetic. Thus, the usual arithmetic conversion will be performed. What are the usual arithmetic conversions?

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



Okay, the first whole promotions are done on each operand. How are entire promotions executed?

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

y

is of type signed char

, so it is first promoted to int

after whole promotions, and x

is of type unsigned int

and remains unsigned int

.

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

Conventional Arithmetic Conversions (Set) (C99, 6.3.1.8p1) "Otherwise, both operands are converted to an unsigned integer corresponding to the type of the signed integer operand."

unsigned int

has the same conversion rank as the type int

(remember, signed char

was promoted to int

), so promoted y

will be converted from int

(after being promoted) to unsigned int

. For information, conversion integers are defined in (C99, 6.3.1.1p1). As you can see, it unsigned int

wins for int

normal arithmetic conversions, another way to say it is to say which unsigned

is sticky.

Now, how is the value int

-1

( signed char

-1

after it promoted to int

) converted to a value unsigned int

? `. Here's what C says about integer conversion in this particular case:

Integer conversions (C99, 6.3.1.3p2) "Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting more than the maximum value that can be represented to the new type until the value is in the range of the new type. "

This paragraph is written in such a way that its meaning does not depend on the signed number. For the two complementary views, this means the value is int

-1

converted to (UINT_MAX + 1) - 1

, which is equal to UINT_MAX

. So, in our particular case

x > y

      

equivalent to

1U > UINT_MAX

      

equivalent to

0

      

+10


source


If you are comparing variables that are not of the same type, one of them must be coerced into the type of the other before the comparison is made.

"Shorter" types will be promoted to "longer" types.

In this case, signed char y

will be converted to unsigned int

with value UINT_MAX

.



In particular, assuming the compiler is using 32-bit ints

:

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

      

Consequently, x < y

.

+7


source


Not 1> -1?

This is if you don't use values unsigned

. In the world, the unsigned

smallest values ​​are zero and one. Anything else is larger, and the language clearly states what unsigned(-1)

is the largest unsigned value.

+1


source







All Articles