【问题标题】:What is the possible use for "#define for if (false) {} else for"?“#define for if (false) {} else for”的可能用途是什么?
【发布时间】:2010-11-02 08:41:26
【问题描述】:

在另一个问题中,我刚刚发现了这颗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++) {...}

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

【问题讨论】:

    标签: c c-preprocessor


    【解决方案1】:

    这是为了修复旧版本 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 提供了一个作用域,就好像它是在循环外声明的一样,它允许您在循环完成后继续使用它。这导致代码如上面的sn-p。在更符合标准的编译器中,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 不会导致无限递归,因为预处理器不会递归替换您当前定义的宏。在这种情况下,它只会进行一次替换。

    【讨论】:

      【解决方案2】:

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

      据我了解

      for(int i=0...){.....} //稍后在同一函数中的同一范围级别 for(int i=0...){...}

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

      如果 for 语句包含在 if 语句中,编译器会正常工作,因此不会出现重新定义错误(显然它解释了 'if' 而不是 'for' 的范围级别)

      【讨论】:

      • 什么是相关性?我不明白。此外,我不会说这是一个错误。这不是作用域的工作方式吗?
      • 是的,这听起来更真实。问:他们为什么要使用 if (false) {} 条件而不是简单的 if(1)。
      • MSVC 6.0 早于 C99 标准 AFAIK...“VC 6 早于一些标准。它具有“扩展”,一旦定义了“i”,它就会一直存在到函数结束。”
      • 只输入if(1) for 将是一个错误。假设您有代码 if(condition) for(...) { }; else do_happy_thing(); - 现在您的代码已损坏,您将很难找出原因。
      【解决方案3】:

      因为默认情况下,msvc 编译器错误地处理了 for 语句中声明的变量范围。为避免这种行为,您必须关闭 microsoft 扩展,这会使 ms 标头无法编译。

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

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

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

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

      【讨论】:

        【解决方案4】:

        效果已经描述了。

        拥有它的原因是将 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 行为更标准的小技巧。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-04-02
          • 2021-09-16
          • 2023-03-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多