3

Possible Duplicate:
unsigned int and signed char comparison

int j = 10;
unsigned int i = 10;
if( j > -1 )
    printf("1\n");
else
    printf("2\n");
if( i > -1 )
    printf("3\n");
else
    printf("4\n");

The output is :

1
4

I've traced into the assembly and the comparation is similar:

cmp     dword ptr [ebp-10h],0FFFFFFFFh
...
cmp     dword ptr [ebp-14h],0FFFFFFFFh

But still don't understand why one is true and the other is false.

IMO the cpu have no idea whether dword ptr is signed or not.

So how does it work under the hood?

UPDATE

anyone can explain it in assembly level?

Community
  • 1
  • 1
kern
  • 2,295
  • 4
  • 17
  • 15

7 Answers7

4

In the following code:

if( i > -1 )
    printf("3\n");
else
    printf("4\n");

the -1 is converted to an unsigned int, which is the biggest unsigned int and clearly larger than 10.

On my machine the following code

#include <stdio.h>
int main()
{
  unsigned int i = -1;
  printf("%u\n", i);
  return 0;
}

Yields: 4294967295

rtn
  • 127,556
  • 20
  • 111
  • 121
  • 1
    To expand a little, when a signed/unsigned comparison occurs, both types are always converted to unsigned. When such a conversion takes place, the bit representation is not changed. While it is not specified in the C++ standard, the most common signed-integer representation is two's-complement, which basically implicitly subtracts half the largest possible unsigned value from the unsigned bit representation. Your compiler should warn you about this if you enable them. – Steve Howard May 28 '11 at 14:21
  • 1
    This question is tagged C. `std::cout`, `` is not C. – Prasoon Saurav May 28 '11 at 14:25
  • @Prasoon: It was only to illustrate what happens when -1 is converted to an unsigned value. Changing to pure C :) – rtn May 28 '11 at 14:31
  • can you explain it in assembly level? – kern May 28 '11 at 14:42
  • @kern: Sorry, that abstraction level is not yet my area :) – rtn May 28 '11 at 14:48
4

As the other answers say, -1 is being converted to unsigned int. Check the jump instructions that follow. One should be "ja" and the other "jg": the unsigned and signed jump instructions.

Neil G
  • 32,138
  • 39
  • 156
  • 257
  • can you elaborate more about the `ja` and `jg` thing? – kern May 28 '11 at 15:01
  • +1 this is the only answer that addresses OP's real question about the asm, and the fact that OP was overlooking the instruction that mattered: the jump. – R.. GitHub STOP HELPING ICE May 28 '11 at 15:46
  • `ja` is the same as `jnc` - it jumps if the carry flag is clear. `jg` depends on the carry, sign, and/or overflow flags (I forget the details but you can look it up or work it out yourself) to implement signed comparison, which is more complex. – R.. GitHub STOP HELPING ICE May 28 '11 at 16:02
  • @kern: The assembly command "cmp" essentially does both signed and unsigned comparison. There is one family of jump statements for signed numbers (jg, jl, jge, jle), and one for unsigned (ja, jb, jae, jbe.) – Neil G May 30 '11 at 03:32
2

When comparing unsigned (i.e i) with signed (i.e -1) the compiler converts the signed value to unsigned.

Converting -1 to unsigned would give a very large value and so the ( i > -1) condition would yield false.

[6.3.1.3/2] (C99)

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.

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
1

Here is your program annotated with all implicit casts it contains:

  int j;
  unsigned int i;
  j = 10;
  i = (unsigned int)10;
  if (j > -1) { printf("1\n"); }
  else { printf("2\n"); }
  if (i > (unsigned int)-1) { printf("3\n"); }
  else { printf("4\n"); }

The first comparison is a comparison of signed ints. The second one is a comparison of unsigned ints.

Regarding the other aspect of your question, there is indeed only one comparison instruction in assembly, but it sets various flags. You test the flag you are interested in for the comparison you are doing (signed, unsigned,...).

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
1

As @Neil G points out, while cmp doesn't know about unsigned vs signed, the conditional jump instructions do.

This is done this way because normal arithmethic instructions (like sub) affect all the relevant condition codes, so then you can do a conditional jump directly, without needing to do any explicit comparison.

Note that cmp is just a sub that doesn't affect the destination.

ninjalj
  • 42,493
  • 9
  • 106
  • 148
0

Before the ">" operator can be evaluated, the operands on both sides need to be (conceptually) converted to the same type. In this case (not sure if it's "standard", or just the whim of the compiler) the -1 is converted to unsigned. -1 is, of course, 0xFFFFFFFF, and that's larger, in an unsigned compare, than 0x0000000A, though in a signed compare it's smaller (because the high-order bit is the sign bit, and signed negative numbers are almost always represented in "twos-complement").

"Under the hood" I suspect that on your CPU the resulting condition code has both signed and unsigned sections, and the difference between the two results has to do with how the condition code is checked, rather than the compare itself.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • This is why it's always wise to explicitly cast numbers to the desired form when doing compares, rather than relying on implicit conversions. It's hard to remember all the implicit conversion rules and predict how they will be applied. – Hot Licks May 28 '11 at 14:19
-1

When you compare an unsigned int and a signed int, the signed int is converted to unsigned int. Converting a negative signed int to a unsigned int is done by adding UINT_MAX + 1.

So -1 is converted to UINT_MAX + 1 - 1 = UINT_MAX which is superior to 10.

See also What's the difference between the "unsigned preserving" and "value preserving" rules?

Tristan
  • 8,733
  • 7
  • 48
  • 96