[英]static assert for C90 on gcc
static_assert()
是自 C11 以来可用的非常棒的功能。
但是,对于 C11 之前的编译器,必须模拟此功能。 这并不难,网上有很多例子。
例如 :
#define STATIC_ASSERT(CONDITION, MSG) \
typedef char static_assert_##MSG[(CONDITION)?1:-1]
这使得在条件中传输错误消息成为可能,如果它被触发,这可以方便地解释发生了什么问题。
但是,这个MSG
与C11
的static_assert()
有很大不同:
这与C11
的static_assert()
如此不同,以至于似乎不可能创建一个宏来根据编译器在C11
和C90
版本之间透明地切换。
为了接受“看起来像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.