无操作 C 宏的"semicolon in global scope"警告的解决方法



在一个可以构建为C或C++的代码库中,我想我应该制作一个宏,以在static_assert构建为C++11或更高版本的情况下利用它。

(注意:我知道在C11之前的C中有一些方法可以做到这一点,至少如果你愿意接受消息参数的话——尽管它不会在任何地方都起作用。但为了便于讨论,我们假设我有一些合理的需求,让它不接受消息,并且至少在一些C构建中是一个无操作的。)

所以我尝试了一个简单的定义:

#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond) 
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond)
#endif

宏中没有分号,目的是在调用站点添加分号。但在迂腐的C警告设置下,这个宏出现在全局范围内导致:

错误:ISO C不允许额外的";"函数外[-Weror=pedantic]

简单的解决方案似乎是去掉调用站点上的分号,并将其放在宏的C++11中。但我想知道:如何在全局范围内生成一个允许在调用位置使用分号的无操作宏(而不与其他警告冲突)?

由于结构的正向声明可以根据需要重复,因此可以使用伪声明:

#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick

@JonathanLeffler说,这应该在旧的编译器中有效,甚至在C11之前…但是:

"如果你有一个C90编译器,如果你在复合语句中的一个语句后面有一个静态断言,它会反对。这不是你主要关心的问题(如果静态断言也可以,它在文件范围内总是可以的),但它不限于在文件范围使用。尽管风险很低。">

对于编译时可能不是完全没有操作的相关情况,C11引入了重复typedef的能力。正如在_static_assert()之前链接的关于C中静态断言的帖子中所示,有一些方法可以使用行号或另一个消歧器来绕过旧C的typedef重复

/* Standard indirection to allow concatenation after expansion */
#define CONCAT(a,b) CONCAT_(a,b)
#define CONCAT_(a,b) a##b
#if defined(__cplusplus) && __cplusplus >= 201103L
#define STATIC_ASSERT(cond) 
static_assert((cond), #cond)
#else
#define STATIC_ASSERT(cond) typedef void CONCAT(dummy_unused_,__LINE__)
#endif

只要静态断言每行出现一个,标识符就不会相互冲突。

最新更新