Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Why does the following code output y>x when clearly 1>-1?

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

if(x>y){
    printf("x>y");
}
else {
    printf("y>x");
}

Please explain this result.

share|improve this question
add comment

closed as off topic by tdammers, gnat, maple_shaft Nov 9 '12 at 12:13

Questions on Programmers Stack Exchange are expected to relate to software development within the scope defined by the community. Consider editing the question or leaving comments for improvement if you believe the question can be reworded to fit within the scope. Read more about reopening questions here.If this question can be reworded to fit the rules in the help center, please edit the question.

3 Answers

Implicit type conversion is biting you. Because x is unsigned, y is cast to unsigned as well; because -1 doesn't fit in an unsigned char, it overflows and becomes 255 (the bit-wise unsigned char equivalent of -1), which obviously is larger than -1.

share|improve this answer
    
But how Compiler decide whether unsigned would be cast to signed or vice-versa ? –  Sudhir Nov 9 '12 at 11:08
    
sudhir: It will just do it because it has to. It just can't compare them otherwise at all. The internal bit representation is different and not converting would not make sense too. In fact there isn't really a "good" way to do it for the compiler and it's the job of the programmer to prevent such situations by either using proper datatypes or doing manual conversion when necessary. –  thorsten müller Nov 9 '12 at 11:12
    
@thorstenmüller It means always there would be casting of signed to unsigned. Is there is a possibility of unsigned to signed conversion? –  Sudhir Nov 9 '12 at 11:16
    
@sudhir: yes, of course. You can always cast explicitly to avoid such things. Another thing I've seen a lot is storing individual chars in int variables. –  tdammers Nov 9 '12 at 11:18
    
@thorstenmüller I have one more confusion when Iam removing unsigned from int then the output must be same as by-default int is unsigned.But the output gets reversed.Why so? –  Sudhir Nov 9 '12 at 11:27
show 8 more comments

This is a case where hopefully you are getting a compiler warning about the mixing of an unsigned and unsigned value. It may be even more specific where it talks about an unsigned lvalue and a signed rvalue.

This example underscores the hazards of C and to a lesser extent, C++ (which tends to be a little more strict about type checking, and which offers multiple kinds of casts). If you want to write good quality C code several things can help:

  • As a basic precaution, use compiler options to generate the strictest warnings possible.
  • Very specifically, avoid mixing of signed and unsigned values in comparisons and most calculations. (signed = signed * unsigned OK, signed = signed + unsigned OK, most other mixing, bad).
  • Use printf(), trace(), or inspection of variables in a debugger to better understand where things go wrong. If your program included a statement like printf("x=%d, y=%d/n", x, y); you would see that things went bad as -1 was assigned into y.
  • Study, study, study... C is a demanding language and you should make yourself as expert as possible on the semantics and side-effects of signed and unsigned comparisons and calculations. You also need a very high degree of attention to detail about the range of input values to equations, the possible range of equation results, and whether constants can actually fit into the variables to which they are assigned.
  • When appropriate, use defensive programming techniques like asserts to expose programming problems during development.
share|improve this answer
    
The compiler does not warn. Implicit casts, even narrowing ones, are valid C, and no warning is issued. Explicit casting on variable assignment is seldom required in C. –  tdammers Nov 9 '12 at 11:48
    
To elaborate: gcc 4.7.1 at least does not warn, at least not for signed vs. unsigned char, and it does produce the correct result (i.e., signed -1 tests smaller than unsigned 1) - but it does warn for signed vs. unsigned int (and, consequently, produces the "wrong" result). My guess would be that gcc casts to a larger integer type to do the comparison; I'm unsure though whether this is standard C behavior. –  tdammers Nov 9 '12 at 11:55
add comment

@tdammers answer is correct, let me expand a bit.

The binary representation for negative values assumes the highest bit has value of 1. E.g., all negative 8-bit values look like 1xxx xxxx.

8-bit value for -1 is 1111 1111.

Hence, the very same binary 1111 1111 for unsigned is 255. So, the same binary value can be interpreted two different ways, depending if it is signed or not.

In your case, as @tdammers noticed, your -1 is stored into signed variable, but then implicitly interpreted as unsigned. Of course, 1 < 255, hence the result.

P.S. You should always check compiler warnings. All modern compilers would raise a warning on this matter.

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.