Static assert in C

在C(而不是C ++)中实现编译时静态断言的最好方法是什么,特别强调GCC?


C-1x adds the _Static_assert keyword.

This seems to be implemented in gcc-4.6:

_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: "assert1"" } */

The first slot needs to be an integral constant expression. The second slot is a constant string literal which can be long ( _Static_assert(0, L"assertion of doom!") ).

I should note that this is also implemented in recent versions of clang.


This works in function and non-function scope (but not inside structs,unions).

#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); 
}
  • If the compile time assertion could not be matched, then an almost intelligible message is generated by GCC sas.c:4: error: size of array 'static_assertion_this_should_be_true' is negative

  • The macro could or should be changed to generate a unique name for the typedef (ie concatenate __LINE__ at the end of the static_assert_... name)

  • Instead of a ternary, this could be used as well #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1] which happens to work even on the rusty olde cc65 (for the 6502 cpu) compiler.

  • UPDATE: For completeness sake, here's the version with __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 specific code

    GCC 4.3 (I guess) introduced the "error" and "warning" function attributes. If a call to a function with that attribute could not be eliminated through dead code elimination (or other measures) then an error or warning is generated. This can be used to make compile time asserts with user defined failure descriptions. It remains to determine how they can be used in namespace scope without resorting to a dummy function:

    #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()
    {
    }
    

    And this is how it looks like:

    $ 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

    I know the question explicitly mentions gcc, but just for completeness here is a tweak for Microsoft compilers.

    Using the negatively sized array typedef does not persuade cl to spit out a decent error. It just says error C2118: negative subscript . A zero-width bitfield fares better in this respect. Since this involves typedeffing a struct, we really need to use unique type names. __LINE__ does not cut the mustard — it is possible to have a COMPILE_TIME_ASSERT() on the same line in a header and a source file, and your compile will break. __COUNTER__ comes to the rescue (and it has been in gcc since 4.3).

    #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__)
    

    Now

    STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
    

    under cl gives:

    error C2149: 'static_assertion_failed_use_another_compiler_luke' : named bit field cannot have zero width

    Gcc also gives an intelligible message:

    error: zero width for bit-field 'static_assertion_failed_use_another_compiler_luke'

    链接地址: http://www.djcxy.com/p/73572.html

    上一篇: 什么是正确的方式来初始化一个非常大的结构?

    下一篇: 在C中静态声明