“#define for if(false){} else for”的可能用途是什么?

时间:2009-06-12 03:52:51

标签: c c-preprocessor

在另一个问题中,我刚刚发现了这个 C 智慧的小珍珠:

#define for if (false) {} else for

导致MSVC为一个非常有效的语句吐出“常量表达式”警告:

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

我理解为什么 MSVC抱怨,因为它扩展为:

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

我只是不明白为什么开发人员会使用那个小片段。有人有想法吗?

4 个答案:

答案 0 :(得分:92)

修复旧版Visual C ++(v6.0及更早版本)中的错误。在过去,Visual C ++已经破坏了关于在for语句中声明的变量的范围规则:

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

for(i = 0; ...)
{

}

换句话说,Visual C ++为i提供了一个范围,好像它是在循环之外声明的,并且它允许您在循环完成后继续使用它。这导致代码如上面的代码片段。在更符合标准的编译器中,i不再适用于第二个for循环的定义,因此编译器会发出关于i未定义的错误。

为了解决这个问题,有些人使用了这个宏(或非常相似的等效宏):

#define for if(0) {} else for

这会将for循环更改为:

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

这会将for循环放入一个额外的范围级别,这样无论Visual C ++的错误如何,for循环中声明的任何变量都将超出范围。这可以确保相同的代码在Visual C ++和符合标准的编译器中一致地正确编译,并且错误的代码无法正确编译。

另请注意,如果宏被定义为:

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

然后虽然这会对一些简单的代码产生相同的效果,但它会突然导致以下代码被错误编译:

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

因为如果你扩展宏,你会得到这个:

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

else现在与错误的if匹配!因此,巧妙地使用if(0) {} else代替if(1)可以避免此问题。

最后一点,#define for if(0) {} else for不会导致无限递归,因为预处理器不会递归替换您当前定义的宏。在这种情况下,它只会做一次更换。

答案 1 :(得分:7)

根据快速搜索,MSVC中的一个错误得到了克服。

据我所知,

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

将导致重新定义“i”错误。

如果for语句包含在if语句中,编译器就会按原样运行,这样就不会出现重定义错误(显然它会解释'if'但不是'for'的范围级别)

答案 2 :(得分:2)

因为默认情况下,msvc编译器错误地处理了for语句中声明的变量范围。为了避免这种情况,你必须关闭微软扩展,然后使ms标头不能编译。

我使用(是的,我仍然使用vs6)一个不同的,它不会在vs6中引起警告,尽管英特尔编译器仍然会发现它。

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

我不记得我从哪里得到它,但我怀疑我发明了它; - )

我知道其他答案已经说明了大部分内容,但弹出窗口说要确保你回答这个问题。

答案 3 :(得分:1)

已经描述了效果。

拥有它的原因是将C ++代码移植到MSVC。或者,如果您希望C ++代码能够独立运行,那么它也非常有用。例如,您在Linux / MacOSX上开发它,现在想在MSVC中编译它。

它对C ++本身也非常有用。例如:

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

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

我已经看过MSVC代码,通过以下方式解决了这个问题:

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

for(int i2 = 0; i2 < N; ++i2) {
    // ...
}

或者:

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

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

在这两种情况下(imo)都没那么好。而这个#define是一个小型的黑客,可以使MSVC表现得更加标准。