What is the possible use for the #define parameter for if (false) {} else for ??

In another question, I just noticed this little pearl of C wisdom:

#define for if (false) {} else for 

due to which MSVC issued warnings of "constant expression" for a fairly correct statement:

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

I understand why MSVC complains because it expands to:

 if (false) {} else for (int i = 0; i <= 10; i++) {...} 

I just don’t understand why developers will use this little snippet. Anyone have an idea?

+45
c c-preprocessor
Jun 12 '09 at 3:52
source share
4 answers

This fix the error in older versions of Visual C ++ (v6.0 and earlier). In the past, Visual C ++ violated the scope rules of variables declared inside for statements:

 // This compiles in old versions of Visual C++, but it is in fact INVALID C++ for(int i = 0; ...) { ... } for(i = 0; ...) { } 

In other words, Visual C ++ provides i scope as if it were declared outside the loop, and allows you to continue using it after the loop finishes. This leads to the creation of code, such as the above snippet. In more standards-compliant compilers, i no longer in the scope of the second for loop, so the compiler throws an error about i as undefined.

To fix this, some people used this macro (or very similar, equivalent macros):

 #define for if(0) {} else for 

This changes the for loop to this:

 if(0) { } else for(int i = 0; ...) { ... } 

This puts the for loop in an extra layer of visibility, so that any variables declared in the for loop will subsequently be out of scope, regardless of the Visual C ++ error. This ensures that the same code compiles correctly both in Visual C ++ and in standards compatible with compilers, and that the wrong code does not compile correctly.

Also note that if a macro was defined as follows:

 // DO NOT USE #define for if(1) for 

Then, although this will have the same effect for some simple code, it may lead to incorrect compilation of the following code:

 if(foo) for(...) { ... } else doSomething(); 

Because if you expand the macro, you get the following:

 if(foo) if(1) for(...) { ... } else doSomething(); 

And else now matches the wrong if ! Thus, clever use of if(0) {} else instead of if(1) fixes this problem.

As a final note, #define for if(0) {} else for does not cause infinite recursion, since the preprocessor will not recursively replace the macro that you are currently defining. In this case, he will perform only one replacement.

+92
Jun 12 '09 at 4:41
source share

According to a quick search, this is an error in MSVC that is being overcome.

As far as I understand,

 for (int i = 0 ...) {.....} 
 // later at the same scope level in the same function
 for (int i = 0 ...) {...}

will override the error "i".

If the for statement is enclosed in an if statement, the compiler works as it should, so that there is no redefinition error (apparently, it interprets the volume levels of "if" but not "for")

+7
Jun 12 '09 at 4:21
source share

Since the msvc compiler does not properly handle the scope of variables declared in the default for statement. To avoid this behavior, you had to disable Microsoft extensions, which then did not compile ms headers.

I use (yes, I still use vs6) another that does not raise a warning in vs6, although the Intel compiler still notices it.

 #define for switch(0) case 0: default: for 

I can’t remember where I got it from, but I doubt that I came up with it; -)

I know that other answers are already talking about this, but a pop-up message tells you to answer the question.

+2
Dec 14 '11 at 20:45
source share

The effect has already been described.

The reason for this is the porting of C ++ code to MSVC. Or it is also very useful if you want your C ++ code platform not to depend. For example, you developed it on Linux / MacOSX and now you want to compile it into MSVC.

And it is also very useful for C ++ itself. For example:

 for(std::set<Foo>::iterator i = myset.begin(); i != myset.end(); ++i) { // ... } for(int i = 0; i < N; ++i) { // ... } 

I saw MSVC code that worked around this by doing either:

 for(std::set<Foo>::iterator i1 = myset.begin(); i1 != myset.end(); ++i1) { // ... } for(int i2 = 0; i2 < N; ++i2) { // ... } 

Or:

 {for(std::set<Foo>::iterator i = myset.begin(); i != myset.end(); ++i) { // ... }} {for(int i = 0; i < N; ++i) { // ... }} 

In both cases (imo) is not so nice. And this #define is a small hack to make MSVC more standard.

+1
Oct 26 '09 at 15:06
source share



All Articles