在浏览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所必需的。但为什么这种特殊的呢?特别是,空括号,虚假条件,做......而?我可以很好地掌握一些语法警告?
答案 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。谢谢!