2009-06-12 43 views
45

在另外一个问题,我刚才发现的这个小珍珠Ç智慧:“#define for if(false){} else for”的可能用途是什么?

#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++) {...} 

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

回答

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环成这是一个额外的范围,所以在for循环中声明的任何变量都将超出范围,而不管Visual C++的错误。这确保相同的代码在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不会导致无限递归,因为预处理器不会递归地替换您当前定义的宏。在这种情况下它只会做一个替换。

7

根据快速搜索它是一个MSVC中的错误被克服。

据我了解,

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

会导致 '我' 的错误的重新定义。

如果for语句被封闭在一个if语句,编译器的工作,因为它应该让没有重新定义错误(显然它解释“如果”,但不是“对”的范围水平)

+0

什么是相关性?我不明白。此外,我不会说这是一个错误。这不是范围工作的方式吗? – 2009-06-12 04:30:09

+0

是的,这听起来更真实。问:他们为什么会把if(false){}条件而不是简单的if(1)。 – 2009-06-12 04:31:47

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的行为更加标准。

2

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

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

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

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

我知道其他的答案已经说这个最,但弹出说要确保你回答了这个问题。