no-op C宏的"全局范围分号"警告的解决方法

Hos*_*ork 12 c static-assert c89

在可以构建为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
Run Code Online (Sandbox Code Playgroud)

宏中没有分号,意图是在呼叫站点添加分号.但在迂腐的C警告设置下,此宏出现在全局范围内会导致:

错误:ISO C不允许额外的';' 函数之外[-Werror = pedantic]

简单的解决方案似乎是从分支中取出分号,并将其放在宏的C++ 11端.但我想知道:你如何在全球范围内制作一个无操作宏,它允许在呼叫站点使用分号(不会发出其他警告)?

Sto*_*ica 14

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

#define STATIC_ASSERT(cond) struct GlobalScopeNoopTrick
Run Code Online (Sandbox Code Playgroud)

@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
Run Code Online (Sandbox Code Playgroud)

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

  • 您也可以使用`struct StaticAssertSurrogate`作为替换文本,它将适用于早于C11的编译器(这时可以重复一个typedef).结构标签是否作为真实结构类型存在甚至无关紧要. (4认同)
  • 不需要`__LINE__`或连接.类型定义可能会重复,因此任何不会被使用的名称都可以; 一个人可以使用`typedef void VoidTypeKludge`. (3认同)