【问题标题】:for or while loop inside #define directive#define 指令中的 for 或 while 循环
【发布时间】:2011-08-11 05:12:16
【问题描述】:

如何在 C 中的 #define 指令中编写 for/while 循环?

【问题讨论】:

  • 您认为这是个好主意吗?短函数有什么问题?例如,函数不必将迭代变量泄漏到使用它的作用域中......
  • @delnan:虽然我同意在几乎所有情况下都应该优先使用函数而不是宏,但要求 for 循环的声明(第一部分)不能泄露到外部。
  • @Thomas Edleson:考虑一下,是的,你是对的。即使在您无法使用for (int i = 0; ...) 的旧语言版本中,将其包装在do { } while (0) 中也会创建一个新的范围。
  • @delnan:为什么不把它包在{...}中; do/while 是多余的。

标签: c for-loop c-preprocessor


【解决方案1】:
#define something for(;;) printf("hooray, i'm in infinite loop!");


int main() { something }

【讨论】:

  • C 不需要在 main 中使用 return 语句吗?
  • 这与手头的主题无关。
  • @AndrewMedico:破碎的例子不相关?
  • 我不确定是否需要,但是是的,返回某些东西至少是一个好习惯。
【解决方案2】:

您可能正在寻找 \ 以跨多行继续宏定义:

#define LOOP(start, end)                  \
  for (int i = (start); i < (end); i++) { \
    printf("%d\n", i);                    \
  }

【讨论】:

    【解决方案3】:

    由于 C 不要求语句位于单独的行中,因此您可以简单地将其组合成一长行:

    #define M while (...) { ...; ...; }
    

    或者您可以在宏定义中转义换行符:

    #define M \
      while (...) { \
        ...; \
        ...; \
      }
    

    【讨论】:

      【解决方案4】:
      #define foo(x) do { \
          for(x=0;x<4;x++) x; \
          } while(0) // note lack of trailing ;
      

      或在 gnu c 中:

      #define foo(x) ({ \
          for(x=0;x<4;x++) x; \
          })
      

      后者可以用作表达式,虽然这个是void类型,因此不是很有用。

      【讨论】:

      • for循环中的宏参数x和控制变量x之间没有冲突吗?为什么do/while(0)
      • @Software Monkey,宏参数x是控制变量,我想保持简单。 do/while(0) 是为了确保它不会被意外用作例如 foo(i) += 12; 或编译器可能乐意允许的其他东西。
      • 嗯?那么foo(index) 尝试执行语句index 4 次,使用index 作为控制计数器变量?
      • 差不多,用处不大。
      • @Software Monkey:提问者没有具体说明循环应该做什么,大概可以稍后填写。
      【解决方案5】:

      简短的回答是“不要”。但是,如果您必须这样做,看在所有神圣事物的份上不要这样做:

      #define FOREACH(start, end)                         \
            for (; (start) < (end); (start)++)            \
            {                                             \
              // do something interesting                 \
            }                                             
      

      到处都是坏的juju。注意start必须对应一个左值;您不能将其称为FOREACH(1,10)FOREACH((a+b), c)FOREACH(x++,y++)。所有这些都会导致编译时错误(++ 的操作数必须是左值,1a+bx++ 都不符合条件)。将其称为FOREACH(x, y++) 会做您真正不希望它做的事情。同样,您也不想将其称为FOREACH(x, y())

      你可以在一定程度上防范这些问题,比如

      #define FOREACH(start, end)                        \
      do {                                               \
        int i;                                           \
        int j = end;                                     \
        for (i = start; i < j; i++)  {                   \ 
          // do something interesting                    \
        }                                                \
      } while (0)
      

      本质上,您正在创建与宏参数相对应的局部变量。这可以防止 start 不是左值,并防止 end 具有被应用的副作用或成为每次迭代都被调用的函数。

      但如果你想封装一个经常被调用的循环,把它放在它自己独立的函数中。它更安全,更易于理解和维护。

      【讨论】:

        【解决方案6】:

        这将是一个更通用的 for 循环

        #include <stdio.h>
        #include <string.h>
        
        #define for_loop(start, end, incr) for(i = start; \
                                                i < end;  \
                                                 i += incr)
        
        int main()
        {
          int i=0, j=5;
        
          for_loop(i, j, 1)
            printf("%d\n", i+1);
        
          return 0;
        }
        

        【讨论】:

        • 非常简洁,同时仍然易于阅读,而且用途广泛(不像公认的答案,需要针对不同的执行进行不同的声明)。干得好!
        猜你喜欢
        • 2011-02-03
        • 2014-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-21
        • 1970-01-01
        • 2021-07-27
        相关资源
        最近更新 更多