c++visual-studio-2012

strange behavior in for loop - a bug?


I'm working with Visual Studio 2012 on a Windows 7 machine and when trying to run the following code snippet (compiled with the default VC11 C++ compiler in x64 mode) the assertion fails, which means, that the inner loop is never entered:

void loopTest1()
{
    const unsigned int k = 1;

    for (int m=0; m<3; ++m)
    {
        int acc = 0;

        for (int n=m-k; n<=m+k; ++n)
        {
            if (n<0 || n>=3) continue;

            ++acc;
        }

        assert (acc>0);

        cout << "acc: " << acc << endl;
    }
}

Now I change the inner loop's end condition:

void loopTest2()
{
    const unsigned int k = 1;

    for (int m=0; m<3; ++m)
    {
        int acc = 0;

        int l = m+k; // this line was added
        for (int n=m-k; n<=l; ++n) // m+k was replaced by l
        {
            if (n<0 || n>=3) continue;

            ++acc;
        }

        assert (acc>0);

        cout << "acc: " << acc << endl;
    }
}

Then I get the correct result:

acc: 2
acc: 3
acc: 2

When I replace the const unsigned int k by a hard-coded 1, it works, too:

void loopTest3()
{
    //const unsigned int k = 1;

    for (int m=0; m<3; ++m)
    {
        int acc = 0;

        for (int n=m-1; n<=m+1; ++n) //replaced k with 1
        {
            if (n<0 || n>=3) continue;

            ++acc;
        }

        assert (acc>0);

        cout << "acc: " << acc << endl;
    }
}

Does the compiler perform some false optimizations? Or is there any specific reason, why the behavior in the first case is at least unexpected?


Solution

  • Your int m is going to be promoted to an unsigned int. On the first loop, that means m-k is equal to -1 as an unsigned value, which is the maximum unsigned value and obviously greater than m+k (when n is compared, it gets promoted). To put it in perspective, you'll end up with n being an unsigned representation of -1 and m+k being 1. Of course when you store that -1 unsigned into a signed integer, it overflows and is technically undefined behaviour. It's most likely keeping its -1 representation and then being promoted back to a max unsigned value.

    Here's a summary of sorts of the first iteration:

    Iteration 1:
    m: 0
    k: 1u
    n=m-k: -1u = max uint, stored into signed int
    m+k: 1u
    n<=m+k --> max uint <= 1u

    In your second example, n is not promoted when compared to the other signed integer and it compares two signed integers. In your third, nothing is unsigned.