在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

    下一篇: macros defined in linux kernel.h file