What is the possible use for "#define for if (false) {} else for"?
Asked Answered
N

4

46

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

#define for if (false) {} else for

which caused MSVC to spit out "constant expression" warnings for a quite valid statement:

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

I understand why MSVC is complaining because it expands to:

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

I just don't understand why the developers would use that little snippet. Anyone have an idea?

Natter answered 12/6, 2009 at 3:52 Comment(0)
M
96

It's to fix a bug in old versions of Visual C++ (v6.0 and earlier). In the past, Visual C++ had broken scope rules about 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++ gives i a scope as if it were declared outside the loop, and it lets you continue using it after the loop is done. This lead to code such as the above snippet. In more standards-compliant compilers, i is no longer in scope at the definition of the second for loop, so the compiler issues an error about i being 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 into this:

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

This puts the for loop into an extra level of scope, so that any variables declared in the for loop will be out of scope afterwards, regardless of Visual C++'s bug. This makes sure that the same code compiles correctly consistently in both Visual C++ and standards-compliant compilers, and that incorrect code does not compile correctly consistently.

Also note that if the macro were instead defined as so:

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

Then although that would have the same effect for some simple code, it would suddenly cause the following code to be compiled incorrectly:

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

Because if you expand the macro, you get this:

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

And the else now matches up with the wrong if! So, the clever use of using if(0) {} else instead of if(1) avoids this problem.

As a final note, #define for if(0) {} else for does not cause infinite recursion, because the preprocessor will not recursively replace the macro which you are currently defining. It will only do one replacement in this case.

Marras answered 12/6, 2009 at 4:41 Comment(0)
A
8

According to a quick search it's a bug in MSVC that gets overcame.

As I understand it,

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

will cause a redefinition of 'i' error.

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 scope levels of 'if' but not 'for')

Askari answered 12/6, 2009 at 4:21 Comment(4)
And what is the relevance? I don't get it. Moreover, I wouldn't say it's a bug. Is that not the way scopes work?Diplomatic
yes, this sounds more realistic. Q. Why would they put the if (false) {} condition instead of a simple if(1).Contagion
MSVC 6.0 predated the C99 standard AFAIK... "VC 6 predates some of the stds. It has the 'extension' that once 'i' is defined it exists until the end of the function."Askari
Putting just if(1) for would be a bug. Suppose you had the code if(condition) for(...) { }; else do_happy_thing(); - now your code is broken and you will have a fair amount of trouble figuring out why.Davita
S
3

Because the msvc compiler incorrectly handles the scope of variables declared in the for statement by default. To avoid this behaviour, you had to turn off microsoft extensions which then made the ms headers not compile.

I use (yes, i still use vs6) a different one which does not cause the warning in vs6, although the Intel compiler still spots it.

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

I can't remember where I got it from, but I doubt that I invented it ;-)

I know the other answers already say most of this, but the pop-up says to make sure that you answer the question.

Staub answered 14/12, 2011 at 20:45 Comment(0)
R
1

The effect was already described.

The reason to have it is to port C++ code to MSVC. Or it is also very helpfull if you want your C++ code platformindependent. For example, you developed it on Linux/MacOSX and now want to compile it in MSVC.

And it is also very usefull 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 have seen MSVC code which 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) not that nice. And this #define is a small hack to make MSVC behave more standard.

Revalue answered 26/10, 2009 at 15:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.