代码之家  ›  专栏  ›  技术社区  ›  paxdiablo

“define for if(false)else for”的可能用法是什么?

  •  45
  • paxdiablo  · 技术社区  · 16 年前

    在另一个问题中,我发现了 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 回复  |  直到 9 年前
        1
  •  92
  •   Paul Groke Chronial    9 年前

    它是在VisualC++(V6.0和更早版本)的旧版本中修复错误。过去,VisualC++已经打破了声明内部变量的范围规则。 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 一个作用域,就好像它是在循环外部声明的一样,它允许您在循环完成后继续使用它。这会导致代码,如上面的代码片段。在更多符合标准的编译器中, 不再在第二个定义的范围内 对于 循环,因此编译器发出一个关于 未定义。

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

    #define for if(0) {} else for
    

    这改变了 对于 循环如下:

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

    这使 对于 循环到一个额外的范围级别,以便在 对于 循环不会超出范围,不管VisualC++的bug。这确保了相同的代码在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 不会导致无限递归,因为预处理器不会递归替换当前定义的宏。在这种情况下,它只做一个替换。

        2
  •  7
  •   Earlz    16 年前

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

    据我所知,

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

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

    如果for语句包含在if语句中,编译器将按其应该的方式工作,这样就不会出现重新定义错误(显然它解释了“if”而不是“for”的作用域级别)

        3
  •  2
  •   Richard Broadhurst    13 年前

    因为MSVC编译器在默认情况下错误地处理在for语句中声明的变量范围。为了避免这种行为,您必须关闭Microsoft扩展,然后使MS头不能编译。

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

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

    我不记得是从哪里弄来的,但我怀疑是我发明的;-)

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

        4
  •  1
  •   Albert    15 年前

    已经描述了效果。

    其原因是将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)都不太好。这一定义是一个小的黑客行为,使MSVC行为更规范。