2

So I've inherited some code that's about as old as me and I'm tasked with maintaining it. The code was written using Visual C++ 6, so it's not modern by any stretch of the imagination.

Anyway, I decided to try and upgrade the solution (or I guess workspace as Microsoft called it back then) so that I can use it with Visual Studio 2013 and use a somewhat modern IDE (I think I'd rather use Emacs or plain-old notepad over VC++ 6). After having changed the character set for the MFC library, I'm getting a whole bunch of undeclared identifier errors (on the order of about 1100 errors). A LOT of them seem to stem from a temporary variable scoping issue, that has me wondering how on earth this code was allowed to compile previously. I'm seeing a lot of stuff like this:

void MyClass::MyFunc() 
{
    for(int i=0;i<56;i++)
    {
      // do some stuff
    } 

    // command hardware
    for(i=0;i<m_pinfo->vc_num;i++)
    {
      // do some more stuff
    }
}

Miraculously, this code compiles just fine in VC++ 6, but (thankfully) not in VS 2013. Notice how the variable i was declared within the scope of the first for loop, but it was then used again in the second for loop. This kind of code is littered throughout the program.

Using VC++ 6's Goto Definition tool, it's telling me that there's an ambiguity between the variable i (but it still compiles!) and several seemingly unrelated variables and parameters called 'i' that are in separate .cpp files all-together, some of them defined in structures even.

What could be going on here? For all intents and purposes, I cannot see how this code is allowed to compile in VC++6.

Community
  • 1
  • 1
audiFanatic
  • 2,296
  • 8
  • 40
  • 56
  • 3
    That dates back to pre-standard days. Microsoft choose to keep support for this (now non-standard) scoping, you can change it with a compiler switch. – alain Dec 28 '15 at 16:13
  • Gross, I can't believe someone thought this was a good idea, makes for really confusing code. – audiFanatic Dec 28 '15 at 16:16
  • I think the "purpose" of this was to be able to check if the loop completed regularly, or because of a `break` statement. (`if(i == end) ..` after the loop) – alain Dec 28 '15 at 16:20
  • eh, still a pretty bad way to do that IMO. But what do I know, I'm just a youngin' – audiFanatic Dec 28 '15 at 16:21
  • I also think it's bad ;-) – alain Dec 28 '15 at 16:24
  • 1
    Note that even vc++6 actually can conform to the standard in this respect with the /Za switch. Unfortunately with that it can't compile its own headers so it's purely an academic point. – Jerry Coffin Dec 28 '15 at 18:29

2 Answers2

2

It is a extension in MSVC++ 6. Variables declared in a for loop are not accessible outside of the for loop scope per the standard. If you need to get this non standard behavior in newer version on MSVS then you can Enable the /Zc:forScope flag

I would suggest that you fix the for loops so you have standard conforming code. This way people who do not know this extension exists will not be surprised by the code.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • hmm, I'm debating whether or not to do this or just fix the code to conform. Granted, I'm getting a whole bunch of other, seemingly non-related errors when trying to compile in 2013. – audiFanatic Dec 28 '15 at 16:18
  • 1
    @audiFanatic I personally would fix the code to be standard conformant. I would only use the flag if it is something that just cannot be brought up to date(budget reasons, ship date, evil bosses). – NathanOliver Dec 28 '15 at 16:23
  • @RichardHodges Well I've got till April to finish this and I'm hoping the conversion won't take that long haha. Then again I'm converting it for my own usability moreso than a project requirement. – audiFanatic Dec 28 '15 at 16:45
  • @audiFanatic it'll take you 2 days to convert all the illegal for loops. If you leave it in compatibility mode you're just pushing the conversion problem closer to your delivery date - plus producing ill-formed c++ in 2016. This would be an unforgivable error :-) – Richard Hodges Dec 28 '15 at 16:49
  • Yea, I think I'm actually done with the for loops already. Now I'm fixing a bunch of "cannot convert from `const char*` to `LPCWSTR`" errors – audiFanatic Dec 28 '15 at 16:51
  • Cool. That is the best way to handle the situation. – NathanOliver Dec 28 '15 at 16:53
  • 3
    Not *really* a bug/non-standard extension. Just adhering to a pre-standardization specification. This was the original behaviour for C++, but it was realized it was an error and the behaviour changed for the first standard. However Microsoft already had a lot of customers with code written to the old behaviour - so they stuck to it. – Martin Bonner supports Monica Dec 28 '15 at 17:12
  • 1
    @MartinBonner: To be fair to Microsoft, they didn't stick to it. They made it a switch, and later toggled the default. – MSalters Dec 28 '15 at 18:55
  • 3
    Yup. I think MS behaved entirely reasonably. – Martin Bonner supports Monica Dec 28 '15 at 19:50
0

In old C, you could define an int without having to specify its type. I suspect VC++6 to obey this ancient rule and implicitly defining a new i variable for the second loop.

If I'm right, this should also compile:

void MyClass::MyFunc() 
{
    for(i=0;i<56;i++)
    {
      // do some stuff
    } 

    // command hardware
    for(i=0;i<m_pinfo->vc_num;i++)
    {
      // do some more stuff
    }
}

And this should print 1 2 3 4

void MyClass::MyFunc() 
{
    for(i=1;i<3;i++)
    {
      std::cout << i << ' ';
    } 

    // command hardware
    for(;i<5;i++)
    {
      std::cout << i << ' ';
    }
}
YSC
  • 38,212
  • 9
  • 96
  • 149