Last Modification: January 21, 2001

Why doesn't Visual C++ correctly implement for() loop scooping? VC complain about the following code sample:

Func ()
{
    for (int i =0; i<5; i++)
    { ... }
    for (int i =0; i<10;i++)
    { ... }
}
It gives an error on the second for () complaining about i being redefined. Isn't that legal according to the C++ Standard?

Yes, that is what the Standard says. Previously, the definition would be considered occurring outside of the braces, and would be in scope until the end of the outer enclosing braces (until the end of Func() in the example above), so defining i in the second for loop gives a redefinition error.  Under the new rules, the variable definition is considered occurring inside the braces of the for() loop, and it goes out of scope at the end of the for loop, so both variable definitions given above would be needed.

The problem is, unlike most of the new rules the Standard added, implementing this one could break existing code. What's worse, it can break it silently.  For example,  consider the following code:


int x;
char *strnchr(char *a, char key, int max)
{
    for (int x = 0; x < max; x++)
        if (a[x] == key)
            break;
    if (x == max)       // here x refers to local variable under old

        return NULL;    // rules, but the global under new rules.

    return(&a[x]);
}

In light of problems like this, and the large body of their own exist code that would break under the new rules, Microsoft settled on a compromise plan.  The new rules would be implemented in "ANSI" mode (/Za), but would be turned off under the "Microsoft extensions" mode (/Ze, the default). However, this is further complicated be the fact that since the Windows header files, and even some of VC's standard C++ header files depend on the Microsoft Extension just to compile, ANSI mode is nearly unusable.

So, what do you do if you need the new scooping rules?  Well, the following macro has been suggested as a workaround:
#define for  if (0) {} else for
However, using a macro to change the semantics of a program is generally not a good idea, and should only be used in extreme cases, such as when trying to compile code developed under a compiler that implements the new rule. Applying the macro to code developed under the original rule can result in silent behavioral changes, as described above. A compiler that implements the new rule can warn about code whose interpretation differs under the old and new rules, so it's best to wait for proper compiler support, if you can.

Yet another workaround is to enclose each for() sentence in braces, like this:


{
    for ( int i = 0; i < 10; i++ )
    {
        //  ...
    }
}
{
    for ( int i = 0; i < 12; i++ )
    {
        //  ...
    }
}

This effectively creates yeta nother scope that hides the for-loop scooping bug. However, it adds unnecessary scopes and is easy to forget to close one of them or them alltogether.