Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparison operation on unsigned and signed integers

See this code snippet

int main() {   unsigned int a = 1000;  int b = -1;  if (a>b) printf("A is BIG! %d\n", a-b);  else printf("a is SMALL! %d\n", a-b);   return 0; }    

This gives the output: a is SMALL: 1001

I don't understand what's happening here. How does the > operator work here? Why is "a" smaller than "b"? If it is indeed smaller, why do i get a positive number (1001) as the difference?

like image 350
Gitmo Avatar asked Jan 18 '10 09:01

Gitmo


People also ask

How do you compare signed and unsigned integers?

A 1-byte unsigned integer has a range of 0 to 255. Compare this to the 1-byte signed integer range of -128 to 127. Both can store 256 different values, but signed integers use half of their range for negative numbers, whereas unsigned integers can store positive numbers that are twice as large.

What happen when a signed negative integer is compared with an unsigned integer?

If Data is signed type negative value, the right shifting operation of Data is implementation-dependent but for the unsigned type, it would be Data/ 2pos. If Data is signed type negative value, the left shifting operation of Data shows the undefined behavior but for the unsigned type, it would be Data x 2pos.

Can we compare signed and unsigned int in C?

One of the several ways in which 2's complement is convenient, is that C (un)signed conversions don't change the bit pattern. That's particular to 2's complement: the C conversions to unsigned types are defined in terms of modulo arithmetic, not in terms of bit pattern.

Is it suggested to compare signed and unsigned numbers in C++?

You decide if need an unsigned comparison or a signed comparison, if you do not decide, this is code that does meet the standard it should because the computer can only do comparison of one of these 2 kind (signed or unsigned), and never of another kind; once you have decided, you make sure, both side of the comparison ...


2 Answers

Binary operations between different integral types are performed within a "common" type defined by so called usual arithmetic conversions (see the language specification, 6.3.1.8). In your case the "common" type is unsigned int. This means that int operand (your b) will get converted to unsigned int before the comparison, as well as for the purpose of performing subtraction.

When -1 is converted to unsigned int the result is the maximal possible unsigned int value (same as UINT_MAX). Needless to say, it is going to be greater than your unsigned 1000 value, meaning that a > b is indeed false and a is indeed small compared to (unsigned) b. The if in your code should resolve to else branch, which is what you observed in your experiment.

The same conversion rules apply to subtraction. Your a-b is really interpreted as a - (unsigned) b and the result has type unsigned int. Such value cannot be printed with %d format specifier, since %d only works with signed values. Your attempt to print it with %d results in undefined behavior, so the value that you see printed (even though it has a logical deterministic explanation in practice) is completely meaningless from the point of view of C language.

Edit: Actually, I could be wrong about the undefined behavior part. According to C language specification, the common part of the range of the corresponding signed and unsigned integer type shall have identical representation (implying, according to the footnote 31, "interchangeability as arguments to functions"). So, the result of a - b expression is unsigned 1001 as described above, and unless I'm missing something, it is legal to print this specific unsigned value with %d specifier, since it falls within the positive range of int. Printing (unsigned) INT_MAX + 1 with %d would be undefined, but 1001u is fine.

like image 185
AnT Avatar answered Oct 10 '22 11:10

AnT


On a typical implementation where int is 32-bit, -1 when converted to an unsigned int is 4,294,967,295 which is indeed ≥ 1000.

Even if you treat the subtraction in an unsigned world, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001 which is what you get.

That's why gcc will spit a warning when you compare unsigned with signed. (If you don't see a warning, pass the -Wsign-compare flag.)

like image 23
kennytm Avatar answered Oct 10 '22 10:10

kennytm