Reputation: 17866
Consider this C code:
#include "stdio.h"
int main(void) {
int count = 5;
unsigned int i;
for (i = count; i > -1; i--) {
printf("%d\n", i);
}
return 0;
}
My observation/question: the loop never gets executed. But if I change the data type of i from unsigned int to int, everything works as expected.
I've been thinking of unsigned ints as values that "wrap around" when you try to keep subtracting from them. So, when i is zero and I subtract 1, it would wrap around to UINT_MAX. And since its value is never negative, this would be effectively an endless loop. (And this is exactly what happens when I change the comparison from i > -1 to i >= 0.)
There is a fault somewhere in my logic, as the loop never gets executed if i is unsigned, and I'm comparing it to -1. Either the compiler optimizes it away somehow or the runtime values behave differently from what I expect.
Why does the loop not get run?
Upvotes: 5
Views: 4023
Reputation: 46233
-1 becomes UINT_MAX
in unsigned comparisons. As no number is greater than that, the loop condition is never true and the loop is never entered.
If you change it to Actually you probably just shouldn't be using unsigned in this case :-)i >= 0
, that should work as expected.
Upvotes: 0
Reputation: 320747
When you mix signed and unsigned operands of the same width in a "type-symmetrical" binary operation (like +
, *
or >
in your example), the unsigned type "wins" and the operation is evaluated in unsigned domain. I.e. signed operand gets converted to unsigned type.
In your example the integer constant has type signed int
, while i
has type unsigned int
. Operands have the same width, so in your example i > -1
is interpreted as i > (unsigned) -1
, which is equivalent to i > UINT_MAX
. This is why your loop is never executed.
Upvotes: 3
Reputation: 279395
In i > -1
, the -1 is converted to unsigned int
, resulting in the value UINT_MAX
. i
is never bigger than that value, so the loop body never executes.
You might find that you can persuade your compiler to warn you about this: use of an always-true or always-false expression in a conditional context. But that still wouldn't help you if you'd written i > -2
, so you may also find you can enable a warning for all mixed-sign comparisons.
Note that in C, arithmetic is always performed with operands of equal type. This includes comparisons but IIRC not the shift operators. If the operands are of different type, as in this case, then at least one of them is converted to make them the same type. The rules for working out the destination type are in 6.3.1.1/2 and 6.3.1.8/1.
Upvotes: 19
Reputation: 39925
Whether you are dealing with unsigned or signed numbers, -1 will always be compiled as 0xffffffff. The processor has both signed and unsigned comparison flags. When comparing that number to 5, the signed flags will treat it as -1 and say it is less, but the unsigned flags will treat it as a large number and say it is greater. Since that number is also the same as UINT_MAX, your comparison will be false for all unsigned numbers.
Upvotes: 1