1

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?

Alnitak
  • 334,560
  • 70
  • 407
  • 495
912M0FR34K
  • 121
  • 1
  • 3
  • 11
  • Assigning -1 to a signed variable isn't going to work. – talonmies Jan 28 '12 at 21:38
  • 3
    Welcome to StackOverflow. Please use proper English sentences such as "Why do I get this output?" rather than SMS-speak "Y do i get this output?". Please also read the [FAQ](http://stackoverflow.com/), especially the section [How do I ask questions here?](http://stackoverflow.com/faq#howtoask) – Jonathan Leffler Jan 28 '12 at 21:38
  • @talonmies - Sure it will. Signed means you can have a sign. – Polynomial Jan 28 '12 at 21:38
  • @QuentinUK - Actually, `unsigned x` defaults to `int`, so it'll be `-2^31` – Polynomial Jan 28 '12 at 21:39
  • @polynomial, I thought it might be, that's why I only made a comment not an answer. – QuentinUK Jan 28 '12 at 21:42
  • @JonathanLeffler Sorry, I shall read the FAQ and will also make sure not to repeat this mistake again. Thank you. – 912M0FR34K Jan 28 '12 at 21:42
  • @QuentinUK - In future it might be more prudent to check such things before stating them as fact. – Polynomial Jan 28 '12 at 21:43
  • @Polynomial assuming a 32 bit default `int` size... you should check that ;-) – Alnitak Jan 28 '12 at 21:43
  • @Alnitak - "for C and C-derived languages on 64-bit machines, 'int' variables are still 32 bits wide, but long integers and pointer are 64 bits wide." - Source: http://en.wikipedia.org/wiki/64-bit#64-bit_data_models – Polynomial Jan 28 '12 at 21:47
  • @Polynomial _usually_, but they're not required to be. On embedded systems you can still get `sizeof(int) == sizeof(short)`. – Alnitak Jan 28 '12 at 21:51
  • @Alnitak - That's true, but I was referring to the kind of systems that a newbie developer will be using, e.g. Linux, Windows, UNIX, AIX, etc. – Polynomial Jan 28 '12 at 21:54
  • exact duplicate of [Why is an unsigned int 1 lower than a char y -1?](http://stackoverflow.com/questions/6555690/why-is-an-unsigned-int-1-lower-than-a-char-y-1) – Alnitak Jan 28 '12 at 22:07

3 Answers3

10

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
ouah
  • 142,963
  • 15
  • 272
  • 331
7

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.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Is the conversion done on the `char` side or the `int` side? If it's a binary copy, wouldn't it be `0xFF000000`? – Polynomial Jan 28 '12 at 21:45
  • 1
    @Polynomial no - negative values get sign extended, so `(signed char)-1` (i.e. `0xff`) would be `0xffffffff` when converted to a 32-bit `signed int`, and then when converted to unsigned the resulting value is `UINT_MAX` – Alnitak Jan 28 '12 at 21:46
  • @Alnitak - Ah, interesting. Thanks for the info! :) – Polynomial Jan 28 '12 at 21:49
1

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.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • I wonder whether mathematically there is a "smallest value" for `unsigned`? Its arithmetic is modulo, so it is like a circle. Going one less (`i--`) you end up at `UINT_MAX` again. What is the "smallest" value then? – Johannes Schaub - litb Jan 28 '12 at 22:00
  • 1
    Considering that for `unsigned` `0 < x` is true for all values of x except 0, I would call 0 the smallest value. – Bo Persson Jan 28 '12 at 22:04
  • Comparison operators do not obey modular arithmetic, which makes sense because modular arithmetic does not have an order relation. Instead, comparison operators always behave the laws of normal integer arithmetic *after* their arguments are promoted according to the promotion rules. – R.. GitHub STOP HELPING ICE Jan 28 '12 at 22:26