Search code examples
coptimizationunsigned-integer

Why does C not run a comparison of unsigned int with negative value?


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?


Solution

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