43
int main(void) 
{ 
     unsigned int y = 10; 
     int x = – 4; 
     if (x > y) 
        Printf("x is greater");
     else 
        Printf("y is greater"); 
     getch(); 
     return (0); 
} 

Output: x is greater

I thought the output would be y is greater since it is unsigned. What's the reason behind this?

OcuS
  • 5,320
  • 3
  • 36
  • 45
Slashr
  • 3,139
  • 6
  • 18
  • 13

6 Answers6

47

Because the int value is promoted to an unsigned int. specifically 0xFFFFFFFC on a 32-bit machine, which as an unsigned int is 4294967292, considerably larger than 10

C99 6.3.1.1-p2

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

To perform the conversion:

C99 6.3.1.3-p2

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.

Which basically means "add UINT_MAX+1" (as I read it, anyway).

Regarding why the promotion was to the unsigned int side; precedence:

C99 6.3.1.8-p1

...Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.

Which tells me int vs. unsigned char should work as expected.

Test

int main()
{
    int x = -4;
    unsigned int y = 10;
    unsigned char z = 10;

    if (x > y)
        printf("x>y\n");
    else
        printf("x<y\n");

    if (x > z)
        printf("x>z\n");
    else
        printf("x<z\n");
    return 0;
}

Output

x>y
x<z

Well look at that.

Community
  • 1
  • 1
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • 1
    i wonder why the `unsigned int` `y` doesn't get converted to `signed int` since it is within the range of `unsigned int` – Anirudha Nov 28 '12 at 09:05
  • 6
    The relevant section is actually **6.3.1.8 Usual arithmetic conversions**. It says "... Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type." (`int` and `unsigned int` have equal rank). – melpomene Nov 28 '12 at 09:10
  • Of course not, go ahead and put it in. – melpomene Nov 28 '12 at 09:14
12

A comparison between a signed and an unsigned value will be made in "unsigned space". I.e., the signed value will be converted to unsigned by adding UINT_MAX + 1. In implementation using the 2-complement for negative values, no special handling of the values is required under the hood.

In this example, the -4 is turned into a 0x100000000-4 = 0xFFFFFFFC which is clearly > 10.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • 2
    It is great to get downvoted while still working on the answer... and without notice what the downvoter considers wrong – glglgl Nov 28 '12 at 08:48
  • The behavior is not implementation dependent and has nothing to do with 2's complement. – melpomene Nov 28 '12 at 08:53
  • 1
    No, no, just the opposite. The answer is correct, as all the answers in this page. It's a trivial thing to all experienced C programmers. – Israel Unterman Nov 28 '12 at 08:55
  • No, every answer that mentions "two's complement" is wrong. C doesn't even require two's complement in the runtime, yet the behavior is 100% specified. – melpomene Nov 28 '12 at 08:57
  • 1
    So what if it doesn't require? The implementation does 2's complement. You can cast to unsigned and check the value. – Israel Unterman Nov 28 '12 at 08:59
  • That's not what glglgl's answer says. – melpomene Nov 28 '12 at 09:00
  • @WhozCraig `(-4 + (0xFFFFFFFF+1))` and `0x100000000-4`makes exactly *what* difference? And I didn't claim that 2s comp is mentionned, but systems using it "don't have anything to do", to express it sloppily. – glglgl Nov 28 '12 at 09:09
4

When you compare two values in C, they both must be of the same type. In this case (int and unsigned int) the int value will be converted to an unsigned int first.

Second, unsigned integer arithmetic in C is done modulo the maximum value of that type + 1 (that is, it "loops around" so UINT_MAX + 1 is 0 again and vice versa). Therefore converting negative values to unsigned results in very large numbers.

The relevant section in the standard says:

6.3.1.3 Signed and unsigned integers

2
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.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • +1 I concur on the conversion. Took me a minute to find the reason *why* it is done in the first place (6.3.1.1-p2). The *how* as you have described it here is spot-on. – WhozCraig Nov 28 '12 at 09:08
  • That's actually the wrong part. :-) 6.3.1.1/2 only applies to types "smaller" than int/unsigned int that are used in place of an int/unsigned int. – melpomene Nov 28 '12 at 09:14
4

When you compare an int and an unsigned int the int is converted to unsigned int. The convertion of an int to an unsigned int is done by adding UINT_MAX+1 (note that your int is negative). So actually you are comparing:

if (-3 + UINT_MAX > 10)  //Since -4 is converted to UINT_MAX+1-4

Which is true.

Maroun
  • 94,125
  • 30
  • 188
  • 241
1

The first bit of an int value is used to define if it's a positive or a negative one. (1 = negative, 0 positive) Your both variable are cast into unsigned int before comparison where the 1 in the first bit will be interpreted as part of your number.

this code should work fine :

int main(void) 

 { 

    unsigned int y = 10; 
    int x = – 4; 
    if (x > (int) y) 
    Printf("x is greater");
    else 
    Printf ("y is greater"); 
    getch ( ); 
    return (0); 

 } 
Jeremie
  • 191
  • 9
-2

int x=-4 (2's complement of 4 is 1111 1100 =252) and unsigned int y=10 is(0000 1010 =10) so 252 >10 so -4 is greater than 10.

suren
  • 1,744
  • 2
  • 12
  • 7
  • if thats the case how does int and unsigned int will make the differance? – dilip kumbham Nov 28 '12 at 13:46
  • An int has 32 bits, hence `int x = -4` is actually represented in memory by the bits `1111 1111 1111 1111 1111 1111 1111 1100` (i.e. `0xFFFFFFFC` in hexa notation), which is much more than 252 if interpreted as an unsigned int. – Boris Dalstein Sep 05 '13 at 20:52