"{{}} while(0)"在内核代码中的作用是什么?

gro*_*kus 20 c kernel linux-kernel

可能的重复:
当我们定义一个宏时,do(0)有什么用?
为什么在C/C++宏中有时会出现无意义的do/while和if/else语句?
C多行宏:do/while(0)vs scope block

我已经看到了很多这样的用法,以前我是程序员想要轻松打破一段代码.为什么我们需要在这里执行while {...} while(0)循环?我们试图告诉编译器一些东西吗?

例如,在Linux内核2.6.25中,包含/ asm-ia64/system.h

/*
 * - clearing psr.i is implicitly serialized (visible by next insn)
 * - setting psr.i requires data serialization
 * - we need a stop-bit before reading PSR because we sometimes
 *   write a floating-point register right before reading the PSR
 *   and that writes to PSR.mfl
 */
#define __local_irq_save(x)         \
do {                    \
    ia64_stop();                \
    (x) = ia64_getreg(_IA64_REG_PSR);   \
    ia64_stop();                \
    ia64_rsm(IA64_PSR_I);           \
} while (0)
Run Code Online (Sandbox Code Playgroud)

Ore*_*ost 25

它总是在宏中使用,因此在调用后需要分号,就像调用常规函数一样.

在你的例子中,你必须写

__local_irq_save(1);
Run Code Online (Sandbox Code Playgroud)

__local_irq_save(1)
Run Code Online (Sandbox Code Playgroud)

会导致错误的分号错误.如果不在那里,那就不会发生这种情况.如果它只是一个范围,一个简单的大括号对就足够了.


Joh*_*itb 24

它允许代码显示在这里:

if(a) __local_irq_save(x); else ...;

// -> if(a) do { .. } while(0); else ...;
Run Code Online (Sandbox Code Playgroud)

如果他们只是使用了{ .. }你会得到的

if(a) { ... }; else ...; 
Run Code Online (Sandbox Code Playgroud)

else不再属于任何一个if,因为分号将是下一个语句并将其else与前一个分开if.将发生编译错误.


AnT*_*AnT 11

do{ ... } while(0)构造的目的是将一组语句转换为可以用a终止;的单个复合语句.你会看到,在C语言中,do/while构造有一个奇怪的和不寻常的属性:即使它"作为"复合语句,它;最终会有一个.C中没有其他复合结构具有此属性.

由于这个属性,你可以do/while用来编写多语句宏,它可以安全地用作"普通"函数而不用担心宏内部的内容,如下例所示

if (/* some condition */)
  __local_irq_save(x); /* <- we can safely put `;` here */
else
  /* whatever */;
Run Code Online (Sandbox Code Playgroud)


Toj*_*oji 5

答案已经给出了(因此宏强制;调用时),但是我已经看到过这种语句的另一种用法:它允许在"循环"中的任何地方调用break,如果需要则提前终止.基本上是你的同事程序员不会谋杀你的"goto".

do {
    int i = do_something();
    if(i == 0) { break; } // Skips the remainder of the logic
    do_something_else();
} while(0);
Run Code Online (Sandbox Code Playgroud)

请注意,这仍然相当混乱,所以我不鼓励使用它.