Static assert in C

前端 未结 12 784
感情败类
感情败类 2020-11-22 16:22

What\'s the best way to achieve compile time static asserts in C (not C++), with particular emphasis on GCC?

12条回答
  •  面向向阳花
    2020-11-22 16:59

    Because:

    1. _Static_assert() is now defined in gcc for all versions of C, and
    2. static_assert() is defined in C++11 and later

    The following simple macro for STATIC_ASSERT() therefore works in:

    1. C++:
      1. C++11 (g++ -std=c++11) or later
    2. C:
      1. gcc -std=c90
      2. gcc -std=c99
      3. gcc -std=c11
      4. gcc (no std specified)

    Define STATIC_ASSERT as follows:

    /* For C++: */
    #ifdef __cplusplus
        #ifndef _Static_assert
            #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
        #endif
    #endif
    /* Now for gcc (C) (and C++, given the define above): */
    #define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
    

    Now use it:

    STATIC_ASSERT(1 > 2); // Output will look like: error: static assertion failed: "(1 > 2) failed" 
    

    Examples:

    Tested in Ubuntu using gcc 4.8.4:

    Example 1: good gcc output (ie: the STATIC_ASSERT() codes works, but the condition was false, causing a compile-time assert):

    $ gcc -Wall -o static_assert static_assert.c && ./static_assert
    static_assert.c: In function ‘main’
    static_assert.c:78:38: error: static assertion failed: "(1 > 2) failed"
    #define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
    ^
    static_assert.c:88:5: note: in expansion of macro ‘STATIC_ASSERT’
    STATIC_ASSERT(1 > 2);
    ^

    Example 2: good g++ -std=c++11 output (ie: the STATIC_ASSERT() codes works, but the condition was false, causing a compile-time assert):

    $ g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert
    static_assert.c: In function ‘int main()’
    static_assert.c:74:32: error: static assertion failed: (1 > 2) failed
    #define _Static_assert static_assert /* static_assert is part of C++11 or later */
    ^
    static_assert.c:78:38: note: in expansion of macro ‘_Static_assert’
    #define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
    ^
    static_assert.c:88:5: note: in expansion of macro ‘STATIC_ASSERT’
    STATIC_ASSERT(1 > 2);
    ^

    Example 3: failed C++ output (ie: the assert code doesn't work properly at all, since this is using a version of C++ before C++11):

    $ g++ -Wall -o static_assert static_assert.c && ./static_assert
    static_assert.c:88:5: warning: identifier ‘static_assert’ is a keyword in C++11 [-Wc++0x-compat]
    STATIC_ASSERT(1 > 2);
    ^
    static_assert.c: In function ‘int main()’
    static_assert.c:78:99: error: ‘static_assert’ was not declared in this scope
    #define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
    ^
    static_assert.c:88:5: note: in expansion of macro ‘STATIC_ASSERT’
    STATIC_ASSERT(1 > 2);
    ^

    Full test results here:

    /*
    static_assert.c
    - test static asserts in C and C++ using gcc compiler
    
    Gabriel Staples
    4 Mar. 2019 
    
    To be posted in:
    1. https://stackoverflow.com/questions/987684/does-gcc-have-a-built-in-compile-time-assert/987756#987756
    2. https://stackoverflow.com/questions/3385515/static-assert-in-c/7287341#7287341
    
    To compile & run:
      C:
        gcc -Wall -o static_assert static_assert.c && ./static_assert
        gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert
        gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert
        gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert
      C++:
        g++ -Wall -o static_assert static_assert.c && ./static_assert
        g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert
        g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert
        g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert
    
    -------------
    TEST RESULTS:
    -------------
    
    1. `_Static_assert(false, "1. that was false");` works in:
      C:
        gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
        gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
        gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
        gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
      C++:
        g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
        g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
        g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
        g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  NO
    
    2. `static_assert(false, "2. that was false");` works in:
      C:
        gcc -Wall -o static_assert static_assert.c && ./static_assert             NO
        gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    NO
        gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    NO
        gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    NO
      C++:
        g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
        g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
        g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
        g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES
    
    3. `STATIC_ASSERT(1 > 2);` works in:
      C:
        gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
        gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
        gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
        gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
      C++:
        g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
        g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
        g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
        g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES
    
    */
    
    #include 
    #include 
    
    /* For C++: */
    #ifdef __cplusplus
        #ifndef _Static_assert
            #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
        #endif
    #endif
    /* Now for gcc (C) (and C++, given the define above): */
    #define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
    
    
    int main(void)
    {
        printf("Hello World\n");
    
        /*_Static_assert(false, "1. that was false");*/
        /*static_assert(false, "2. that was false");*/
    
        STATIC_ASSERT(1 > 2);
    
        return 0;
    }
    

    Related:

    1. Use static_assert to check types passed to macro [my own answer]
      1. https://en.cppreference.com/w/cpp/types/is_same
      2. https://en.cppreference.com/w/cpp/language/decltype
    2. Use static_assert to check types passed to macro
    3. How to use static assert in C to check the types of parameters passed to a macro

提交回复
热议问题