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

标签 c c89 static-assert

在可以构建为 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 的能力。正如在 _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

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

关于c - 针对无操作 C 宏的 "semicolon in global scope"警告的解决方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53923706/

相关文章:

c - 哈希表中的读取无效

c - 纪元时间排序器

c - 我是否应该重新声明外部数组的一部分以在模块中使用

c++ - 在类型实例化期间强制触发 static_assert

c - 比 printk() 更好的方法来留下内核模块日志?

c - 如何在C中读取带空格的整行文本

将 long 转换为函数指针?

c - "Strong"通过单元素结构输入 C。编译器会做什么?

c++ - 如何在 Visual Studio 中查看 static_assert 的 'failure source'?

c++ - 在C++函数中计算斐波那契并抛出编译时错误