Brian Carnes

Personal: Home · Directions · Contact Info · MyLinks
Business: Resume · Projects · Coding Info · WorkLinks

Coding Tips

The following has come up a couple of times, and having not seen this answered on the net anywhere, here it is:

Enabling Proper C++ for scoping under Microsoft Visual C++

Anyone who has coded in C++ under a standards-conforming compiler is used to the iteration variable going out of scope at the end of the for block:
	...
	for (int i = 0; i < 5; i++)
	  /* do something */;
	// 'i' is out of scope here, and may be reused
	for (int i = 0; i < 5; i++)
	  /* do something else */;
	...
Alas, this doesn't work under Microsoft Visual C++ versions 4.x, 5.x, 6.x, which give the dreaded
error C2374: 'i' : redefinition; multiple initialization
because they expand:
for (init; cond; expr)
     body 
as:
init; 
while (cond) {
    body 
    expr; 
}
How to fix this? Well, there is an option to disable so-called Microsoft Extensions, via command-line option -Za. This does indeed fix the for-scoping problem, and the above snippet compiles without error. However, if you include some Microsoft headers, such as windows.h, you various errors, such as:
winnt.h(357) : error C2467: illegal declaration of anonymous 'struct'
winnt.h(376) : error C2467: illegal declaration of anonymous 'struct'
winnt.h(1519) : error C2146: syntax error : missing ';' before identifier 'PVOID'
winnt.h(1519) : error C2501: '_inline' : missing storage-class or type specifiers
winnt.h(1519) : fatal error C1004: unexpected end of file found
So using -Za is no good, as Microsoft headers rely upon anonymous structures and other extensions.

Is there a way to get just proper for-scoping without affecting all the other extensions? Not via any compiler options I've found. However, the following preprocessor solution works very well:

as a command line option:
  cl -Dfor="if(0);else for" ...

in a master header file:
  #define for if(0);else for
What does this do? It causes the preprocessor to expand every for statement as an empty if statement that is never executed, and the for block becomes the always executed corresponding else. The correctly scoped if-then-else statement then takes care of wrapping the for block.

Is this safe? for is already a reserved word in C/C++, so the fact that it will be expanded by the preprocessor is safe. The construct is set up so as not to unbalance nested ungrouped if-then-else chains. The construct is also completely optimized away by the compiler.

Note that this is meant to help allow porting standards-compliant C++ code to Microsoft's Compiler. Code written to take advantage of this old-style behavior may recompile with errors, or with silently different behavior under this construct:

for (int i = 0; i < 5; i++)
  /* do something */;
if (i == 5) // rely on i still being in scope, now a compile error
  ...
or worse:
double i=3;
void foo() {
  for (int i = 0; i < 5; i++)
    /* do something */;
  if (i == 5) // now refers to the double, no warning or error!
    ...
So do be aware of the above before applying this to your code. If your code is coming from a modern C++ compiler, the above techniques are just what you want. If you want to apply this technique to your existing body of compiled-only-under-VC++ code, then you need to exercise some caution in applying this fix.
Brian's Quick 'n' Dirty Web