在C中静态声明
在C(而不是C ++)中实现编译时静态断言的最好方法是什么,特别强调GCC?
C-1x添加_Static_assert关键字。
这似乎是在gcc-4.6中实现的:
_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: "assert1"" } */
第一个插槽需要是一个整数常量表达式。 第二个插槽是一个可以很长的常量字符串文字( _Static_assert(0, L"assertion of doom!")
)。
我应该注意到这也是在最近版本的clang中实现的。
这适用于函数和非函数范围(但不在结构,工会内部)。
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
STATIC_ASSERT(1,this_should_be_true);
int main()
{
STATIC_ASSERT(1,this_should_be_true);
}
如果编译时间断言无法匹配,那么GCC sas.c:4: error: size of array 'static_assertion_this_should_be_true' is negative
会生成一个几乎可理解的消息sas.c:4: error: size of array 'static_assertion_this_should_be_true' is negative
该宏可以或应该被更改为为typedef生成一个唯一的名称(即在static_assert_...
名称末尾连接__LINE__
)
而不是三元组,也可以使用#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1]
,即使在生锈的olde cc65上也能正常工作6502 cpu)编译器。
更新:为了完整起见,这里是__LINE__
的版本
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X) COMPILE_TIME_ASSERT2(X,__LINE__)
COMPILE_TIME_ASSERT(sizeof(long)==8);
int main()
{
COMPILE_TIME_ASSERT(sizeof(int)==4);
}
UPDATE2:GCC特定代码
GCC 4.3(我猜)引入了“错误”和“警告”功能属性。 如果通过死代码消除(或其他措施)无法消除具有该属性的函数的调用,则会生成错误或警告。 这可以用来使用户定义的故障描述使编译时间断言。 它仍然可以决定如何在命名空间范围内使用它们而不诉诸虚拟函数:
#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })
// never to be called.
static void my_constraints()
{
CTC(sizeof(long)==8);
CTC(sizeof(int)==4);
}
int main()
{
}
这就是它的样子:
$ gcc-mp-4.5 -m32 sas.c
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true
CL
我知道这个问题明确提到了gcc,但为了完整起见,这里对微软编译器进行了调整。
使用负数大小的数组typedef并不能说服cI吐出一个体面的错误。 它只是说error C2118: negative subscript
。 零宽度位域在这方面表现更好。 由于这涉及到typedeffing结构,所以我们确实需要使用唯一的类型名称。 __LINE__
不切割芥末 - 可能在头文件和源文件的同一行上有COMPILE_TIME_ASSERT()
,并且编译将会中断。 __COUNTER__
来救援(从4.3开始,它已经在gcc中)。
#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond,msg)
typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); }
CTASTR(static_assertion_failed_,__COUNTER__)
现在
STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
在cl
下给出:
错误C2149:'static_assertion_failed_use_another_compiler_luke':命名位字段不能有零宽度
海湾合作委员会也提供了一个可理解的信息:
错误:零位宽度为'static_assertion_failed_use_another_compiler_luke'
链接地址: http://www.djcxy.com/p/73571.html上一篇: Static assert in C