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

Workaround for "semicolon in global scope" warning for no-op C macro

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

(注意:我知道 there are ways to do this in pre-C11 C,至少如果你愿意接受一个消息参数——虽然它不会在任何地方都有效。但为了争论假设我有一些合理的需要让它不接收任何消息,并且至少在某些 C 构建中是空操作。)

所以这是我尝试过的简单定义:

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

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

error: ISO C does not allow extra ‘;’ outside of a function [-Werror=pedantic]

简单的解决方案似乎是将分号从调用点中移除,并将其放在宏的 C++11 端。但我想知道:你如何在全局范围内制作一个允许在调用站点使用分号的无操作宏(没有运行与其他警告冲突)?

由于结构的前向声明可以根据需要重复,因此您可以使用虚拟声明:

#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick

@JonathanLeffler 说这应该适用于较旧的编译器,甚至是 C11 之前的编译器......但是:

"If you have a C90 compiler, it would object if you had a static assert after a statement in a compound statement. This is not your primary concern (it’ll always be OK at file scope if the static assert is OK too), but it isn’t limited to being used at file scope. The risk is low, though"

对于编译时可能 完全 无操作的相关情况,C11 引入了重复 typedef 的功能。正如 post 在 _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

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