#define foo()的目的是做{}而(0)

时间:2014-10-07 11:08:50

标签: c loops

在浏览LinCAN驱动程序的源代码时,我发现一些令我困惑的宏。

#else /*CONFIG_PREEMPT*/
#define can_preempt_disable()      do { } while (0)
#define can_preempt_enable()       do { } while (0)
#endif /*CONFIG_PREEMPT*/

我理解

的用处
do { 
  ...;
  if(condition) break;
  ... 
} while (0); 

使用break作为一种throw。我半理解包装一系列函数,如

#define FOO() do { foo(); bar(); } while (0)

避免使用无括号if进行警告。我有时会理解" no-op陈述"是#define所必需的。但为什么这种特殊的呢?特别是,空括号,虚假条件,做......而?我可以很好地掌握一些语法警告?

2 个答案:

答案 0 :(得分:23)

这是一种通用语法,用于通知编译器应将宏视为语句而不是表达式statements vs expressions)。

在这种情况下,如果您尝试将can_preempt_disable()用作表达式,编译器将提醒您。这意味着我们强制编译时检查can_preempt_disable()被用作语句。编译时检查通常是可取的。

答案 1 :(得分:17)

complete passage from the relevant file是:

#if !defined(CONFIG_PREEMPT_RT) && ( defined(CONFIG_PREEMPT) ||
    (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) )
#define can_preempt_disable preempt_disable
#define can_preempt_enable preempt_enable
#else /*CONFIG_PREEMPT*/
#define can_preempt_disable() do { } while (0)
#define can_preempt_enable() do { } while (0)
#endif /*CONFIG_PREEMPT*/ 

因此,第一部分是你要求抢先保护时获得的代码,否则你会得到空的,无所事事的循环。

我猜他们的写法是出于通常的原因,即确保宏仍然是一个有效的陈述。

定义中不应该有一个终止分号,因为它将在使用这些分号的代码中,例如this function开头:

int c_can_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
{
    can_preempt_disable(); 

    ...

所以,很明显,宏像任何其他函数调用一样使用,分号就在那里调用宏。这很正常。

更新2 :将其定义为;会导致双分号,这至少在我看来是丑陋的。一个空括号对{}可以工作我猜,但这个do/while构造更加惯用,因为它经常用于这样的情况。

更新3 :正如评论中所指出的那样,空支撑对不起作用,因为在调用后你不能放一个分号。 AAH。谢谢!