为什么在宏定义中使用do {} while(0)?

cip*_*hor 15 c c-preprocessor libev

可能重复:
为什么在C/C++宏中有时会出现无意义的do/while和if/else语句?

我遇到了如下代码:

#define ev_io_init(ev,cb,fd,events) \
do { \
  ev_init ((ev), (cb)); \
  ev_io_set ((ev),(fd),(events)); \
} while (0)
Run Code Online (Sandbox Code Playgroud)

我想知道作者为什么在do { } while (0)这里使用.这有什么不同吗?

#define ev_io_init(ev,cb,fd,events) { \
  ev_init ((ev), (cb)); \
  ev_io_set ((ev),(fd),(events)); \
}
Run Code Online (Sandbox Code Playgroud)

BTW:代码来自libev,ev_local.h

moo*_*dow 23

考虑 if( something ) function1(); else function2();

如果function1()实际上是一个宏,那么只{ }需要在使用时省略分号,但是do { } while(0)让你使用与真实函数完全相同的语法.

(根本不使用任何类型的块构造只会生成完全破坏的代码,natch)


Lin*_*een 16

用循环包含代码允许预处理程序指令执行多个语句而不"破坏"if-else-constructs.考虑以下:

#define DO_SOMETHING() a();b();c();

void foo()
{
    // This is ok...
    DO_SOMETHING();
}

void bar()
{
    // ...whereas this would trigger an error.
    if (condition)
       DO_SOMETHING();
    else
       blah();
}
Run Code Online (Sandbox Code Playgroud)

第二个例子打破了if-else-construct,因为三个语句后跟一个else子句.为了使其正确替代,DO_SOMETHING应在附录中附上说明do { ... } while(0).

  • 当然,如果你使用裸线,如果这样的线,你应该打破你的代码...... (3认同)
  • @Simon但不是linux内核编码风格建议我们使用裸线if else行为一个行块?https://www.kernel.org/doc/Documentation/CodingStyle (2认同)
  • @CoderSpinoza显然是这样,如果我要在linux内核上工作,那么我会遵循这种风格.在其他地方,我会避免它. (2认同)
  • 许多 C 代码存储库使用一行 ifs 没有大括号,这完全没问题。 (2认同)

Luc*_*ore 10

A do{}while(0)允许你打破循环:

do{
   expr1;
   foo();
   if ( cond )
      break;
   expr2;
   goo(); 
} while (0);
Run Code Online (Sandbox Code Playgroud)

它与简单块{...}相同,只是您可以在需要时使用该break语句中断执行.你不能在一个简单的代码块中这样做,除非你有多个检查,这可能会很麻烦.由于条件的原因,它仍会执行一次while(0).

  • ......确实如此,但请不要...... (8认同)