7

While browsing some C++ code, I came across the following lines :

for (int i = 0; i < count; i++) {
        if (&array[i].GetData() == el)
            break;
}
if (i < count) {
   // .. Do something
}

I am surpised to see that the loop-counter variable i is accessible outside the loop!

Just to ensure that the i outside the loop was same as the one inside the loop, I changed the loop variable name to i1.

for (int i1 = 0; i1 < count; i1++) {
        if (&array[i1].GetData() == el)
            break;
}
if (i < count) {    // COMPILATION ERROR: Identifier i is undefined
   // .. Do something
}

This resulted in a compilation error for the line if(i < count) :

identifier 'i' is undefined.

What is going on? This is too basic to be a compiler bug. If there was another i in a parent scope, there would have been no compilation error. Am I missing something? I am using Visual Studio 2015.

7
  • 2
    What compilation flags are you using? (e.g.: do you have /permissive and/or /Za turned on?) Commented Apr 11, 2018 at 8:31
  • 2
    Seems like trace residue of the things described here stackoverflow.com/questions/49447957/… Commented Apr 11, 2018 at 8:33
  • 1
    It's a Microsoft compiler "extension". It's enabled by default for historical reasons. Commented Apr 11, 2018 at 8:36
  • 1
    Do you have the /Zc:forScope- (" Force Conformance in For Loop Scope" in the IDE's C++ properties) option set? That causes the MC++ 2015 compiler to use legacy behavior that extends the scope of for loop variables. Commented Apr 11, 2018 at 8:43
  • This is definitely not standard behaviour and you most certainly shouldn't ever count on it. Your compiler with your current flags may accept this, but another compiler, or even just different versions or flags with the same compiler, may not (and honestly, should not imo) Commented Apr 11, 2018 at 8:43

1 Answer 1

10

Visual Studio in the past had the feature that extended the lifetime & accessability of variables declared in the for(...) construct (a holdover from plain C behaviour, before the C++98 standard came into being). This behaviour was enabled by default in the older projects.

Microsoft realized that this (for C++) non-standard conforming behaviour might be undesirable and provided the /Zc:forScope compiler option to control this behaviour (and more recently enabled this switch by default, restoring standard C++ conformity).

Check if the /Zc:forScope is set in your project settings under the C++ -> Language rider. If not, set it.

Note: You also have the option to set /Zc:forScope- there to explicitly enable the non-standard behaviour, in case you have legacy code that relies on it.

Sign up to request clarification or add additional context in comments.

5 Comments

Not just VS - but gcc too. It's from before there was a standard. See stackoverflow.com/questions/49447957/…
Ah, I wasn't aware of that; it is just one those things that can give you the nastiest of surprises (had a very "interesting" bug with a typo in a variable name a long while back - unfortunately the typo matched up with a variable declared in a for(...) earlier. Was quite "fun" trying to find that one.)
I had a go at editing this to remove the implication that MS made a mistake that it was slow to remedy. But I tired of it. There was a time (before C++98?) when the old, C style behavior was the only behavior. The original Cfront (which I used) did it that way. When the standard changed, Microsoft and others were quick to adopt it, but made the old behavior the default, in order not to break existing projects. It was the right thing to do.
@Jive Dadson I've updated my answer to reference that. I just wish they would not have enabled it by default for the C++ projects too (At least I recall using VS2003 - again a long while back -, creating a C++ project and being confused by it)
I was looking over some 17 year old code that fails to compile due to this very behavior. I could not understand why it was compiling in the past. I am surprised that the original author ignored the scoping standard of C++.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.