繁体   English   中英

gcc 上 C90 的静态断言

[英]static assert for C90 on gcc

static_assert()是自 C11 以来可用的非常棒的功能。

但是,对于 C11 之前的编译器,必须模拟此功能。 这并不难,网上有很多例子。

例如 :

#define STATIC_ASSERT(CONDITION, MSG) \
typedef char static_assert_##MSG[(CONDITION)?1:-1]

这使得在条件中传输错误消息成为可能,如果它被触发,这可以方便地解释发生了什么问题。

但是,这个MSGC11static_assert()有很大不同:

  • 它必须是一个词
  • 它必须仅使用标识符字符
  • 它不能是带双引号的字符串

这与C11static_assert()如此不同,以至于似乎不可能创建一个宏来根据编译器在C11C90版本之间透明地切换。

为了接受“看起来像C11 ”的错误消息,也就是带双引号的字符串,我测试了一个新的宏:

#define STATIC_ASSERT(CONDITION, MSG) \
typedef char static_assert[((void)(MSG), ((CONDITION)?1:-1))]

使用,逗号运算符,此宏应接受MSG作为字符串,而忽略它。 但是会在出错的情况下显示出来,这就是本意。

它在clang上工作正常,但在gcc上工作正常: error: variably modified at file scope

我试图理解为什么,如果有解决办法

如果你用 enum-trick 替换 typedef-array-trick,那么你会得到一些似乎同时适用于 clang 和 gcc 的东西:

#define CONDITION 1

#define TOKENPASTE(a, b) a ## b // "##" is the "Token Pasting Operator"
#define TOKENPASTE2(a,b) TOKENPASTE(a, b) // expand then paste
#define static_assert(x, msg) enum { TOKENPASTE2(ASSERT_line_,__LINE__) \
    = 1 / (msg && (x)) }

static_assert( CONDITION, "This should pass");
static_assert(!CONDITION, "This should fail");

这给了我,例如 gcc,在 foo.c 的第 9 行:

foo.c:9: warning: division by zero [-Wdiv-by-zero]
 static_assert(!CONDITION, "This should fail");
 ^
foo.c:9: error: enumerator value for 'ASSERT_line_9' is not an integer constant
 static_assert(!CONDITION, "This should fail");
 ^~~~~~~~~~~~~

(这里使用了 gcc 开关-ftrack-macro-expansion=0 ,因为额外的错误消息没有那么有用,只会增加噪音。)

请注意,仍然需要对名称进行一些修改,但您忽略了这一点。 这里文本ASSERT_line_与变量__LINE__组合在一起。 这确保了一个唯一的名称,前提是:

  • 您不会在一行中使用它两次。
  • 你不要在头文件中使用它(或者相信运气)。
  • 您的代码不会碰巧在其他地方使用像ASSERT_line_9这样的标识符。

对于头文件,您需要在某处添加一个仅包含标识符字符的单词。 例如:

#define static_assert3(x, msg, file) enum { TOKENPASTE2(file,__LINE__) = \
    1 / (msg && (x)) }
#define static_assert(x, msg) static_assert3(x, msg, my_header_h_)

如果这在第 17 行失败,gcc 将给出一个错误,例如:

 error: enumerator value for 'my_header_h_17' is not an integer constant

在头文件中修改的另一种方法是用__COUNTER__替换__LINE__ 我没有使用过它,因为它是非标准的,并且因为 clang 采用它的速度很慢。 但现在已经在 gcc、msvc 和 clang 中使用了大约五年。


您可以尝试使用 typedef-array 想法进行相同的修改,并将逗号运算符替换为&& 然后您的 gcc 错误变为警告。 例如,将您的 Godbolt 示例修改为:

typedef char static_assert_2["hello world!" && (CONDITION) ? 1 : -1];

给出了不需要的warning: variably modified 'static_assert_2' at file scope gcc 的warning: variably modified 'static_assert_2' at file scope

单线

#define STATIC_ASSERT(CONDITION, MSG) { typedef char test[(CONDITION)?1:-1]; (void)(test*) #MSG; } (void)0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM