Search code examples
c++cgcccompiler-optimizationinteger-overflow

C++ while loop optimization not working properly


I have this code segment:

#include <stdio.h>

int main(int argc, const char** argv)
{
    int a = argv[0][0];
    int b = argv[0][1];

    while ((a >= 0) &&
           (a < b))
    {
        printf("a = %d\n", a);
        a++;
    }

    return 0;
}

and I'm compiling it with gcc-4.5 -02 -Wstrict-overflow=5.

The compiler yells at me warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2

What does this mean exactly?

If i am correct, this loop will never cause an overflow, because for a to be incremented, it must be smaller than another integer. If it is bigger, the loop is terminated.

Can anyone explain this behavior to me?


Solution

  • The C++ standard says that if a signed integer calculation produces a result outside the representable range for the type then the behaviour is undefined. Integer overflow is UB. Once UB has happened, the implementation is free to do whatever it likes.

    Many compilers apply optimisations on the explicit assumption that UB does not happen. [Or if it does, the code could be wrong but it's your problem!]

    This compiler is notifying you that it is applying such an optimisation to a calculation where it is unable to determine from analysing the code that UB does not happen.

    Your choices in general are:

    1. Satisfy yourself that UB cannot happen, and ignore the warning.
    2. Allow UB to happen and live with the consequences.
    3. Rewrite the code so UB really cannot happen and the compiler knows it cannot happen, and the warning should go away.

    I would recommend the last option. Simple range tests on a and b should be good enough.


    My guess is that the compiler emits this error because the loop deals with completely unknown values, and it is unable to analyse the data flow well enough to work out whether UB can happen or not.

    We with our superior reasoning power can convince ourselves that UB cannot happen, so we can ignore the error. In fact a careful reading of the error message might leave us asking whether it is relevant at all. Where are these two constant value C1 and C2?

    We might also note that a can never go negative, so why is that test in the loop? I would probably rewrite the code to suppress the error, (but from experience that can be a self-defeating exercise). Try this and see what happens (and avoid unneeded parenthetic clutter):

    if (a >= 0) {
      while (a < b) {
        ...
        ++a;
      }
    }