C 在函数外没有 op 语句

C no op statement outside functions

我的代码包含很多行,例如:

static_assert(sizeof(my_stuct)==42, "check struct size");

并且我想在未实现 static_assert 的编译器上进行编译。所以我希望这些行成为空操作。我试过:

#define static_assert(COND, MSG) 

它工作正常,但我收到 clang 编译器的警告:

warning: extra ';' outside of a function [-Wextra-semi]

是否有一个简单的无操作 C 语句可以在函数外部使用,它以分号终止并且可以重复使用?

目前我的解决方案:

#define static_assert(COND, MSG) extern int __static_assert_dummy__

工作正常但我觉得很丑!

只测试了很快,但是怎么样:

#define static_assert(COND, MSG) extern int _no_static_assertion

什么的?重复 extern 应该没问题。

由于这是 C11 的一个特性,答案很简单:只需检查编译器是否支持 C11。

#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112
  static_assert(sizeof(my_stuct)==42, "check struct size");
#endif 

相反,要在没有标准 C 的情况下使其成为无操作,从而消除对上述编译器开关的需要,是这样的:

#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
  #define static_assert(cond, str) struct dummy_t
#endif 

不过请记住 static_assert 需要 #include <assert.h>,这与 C11 关键字 _Static_assert 不同。

I want to compile on a compiler which has no static_assert implemented. So I want these lines to become no-op.

为什么不将 Lundin 的答案(检查当前编译器 是否实现了 )与 [=12= 的 实现 结合起来](这不难做到)?

PDCLib (which is CC0 许可中复制实现:

/* with dodgy implementations, you could also #ifndef static_assert */
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
#define _PDCLIB_cc( x, y )     x ## y
#define _PDCLIB_concat( x, y ) _PDCLIB_cc( x, y )

#define static_assert( e, m ) enum { _PDCLIB_concat( _PDCLIB_assert_, __LINE__ ) = 1 / ( !!(e) ) }
#endif

对于给定的表达式 e 和消息 m,这声明了一个具有一个成员的匿名枚举,其名称是 _PDCLIB_assert_ 与当前源文件行(__LINE__ )(因此每个源文件可以有多个 static_assert())。如果表达式 e 为真,则此成员设置为 1 除以 1,如果表达式为假,则此成员设置为除以 0,这将导致像这样的输出断言失败:

./path/to/source.c:57:94: warning: division by zero [-Wdiv-by-zero]
 #define static_assert( e, m ) enum { _PDCLIB_concat( _PDCLIB_assert_, __LINE__ ) = 1 / ( !!(e) ) }
                                                                                      ^

./path/to/header.h:571:1: note: in expansion of macro 'static_assert'
 static_assert( false, "test" );
 ^
./path/to/source.c:57:62: error: enumerator value for '_PDCLIB_assert_571' is not an integer constant
...

它并不漂亮,但它完全符合 C89,经过测试且可维护。

随意将 _PDCLIB_* 重命名为您喜欢的任何名称。