cgccstatic-assert

Static assert in C function-like macro


How to implement (compile-time) static assertion in function-like macros ?

There is good discussion, and lot of alternative for the case of injecting static assertion as "C" statement - expanding into variants of static_assert. The challenge in the case of function like object is that I cannot find a way (at least with GCC9) to include static_assert as part of expression.

Consider the following example, where I would like to check that the passed parameter is either green or blue, and would like to have compile time error, if it's neither. This is simplified example, to demonstrate the problem. Actual condition much more complex.

#include <stdbool.h>
#include <assert.h>
#include <stdio.h>

#define GREEN 1
#define YELLOW 2
#define RED 3

#define is_green(color) (color == GREEN ? true : color == YELLOW ? false : _Static_assert(!("Bad Color")))

int main(int argc, char **argv)
{
    bool g = is_green(GREEN) ;
    bool y = is_green(YELLOW) ;
    bool r = is_green(RED) ;                      // Should fail
}

I expect the above to produce compile time assertion error - on the line with 'Should fail' comment. Instead, I'm getting assertional 3 errors on every call to is_green: "expected expression before _Static_assert".

The core issue seems to be that "Static_assert" is not a function - it's more like a statement, therefore it can not be included in expressions, - directly, via a macro or inline function.

Already tried the following:

In all cases, GCC does not allow Static_assert to be part of expression - be it assignment, or function call.

Mu current workaround, is to get compile time alert by putting 0/0 instead of the _Static_assert - GCC produce compile time error - division by zero. This is confusing to the development team.

#define is_green(color) (color == GREEN ? true : color == YELLOW ? false : 0/0 )

Any suggestion ?

To reiterate - goal is to be able to raise compile time assertion for function-like macros. At this time I

Yair


Solution

  • There are two parts to this question.

    1. How to place a declaration like static_assert inside an expression (possibly expanded from a function-like macro)?
    2. How to make static_assert conditionally fired, where the condition is not a preprocessing one (that is, not im an #if or friends)?

    Nornally the answer to both of these question is "you can't".

    However with a bit of chutzpah, you can.

    Remember that C has compound literals. Compound literals look somewhat like cast expressions. They have a type inside. A type can be a struct. Structs have member declarations and... drumroll... static_assert declarations inside. Let's test it!

    #define SUCC ((struct {int z; static_assert(1==1);}){1}, 0)
    #define FAIL ((struct {int z; static_assert(1==2);}){1}, 0)
    
    int main()
    {
      int x = SUCC;
      int y = FAIL; // fails
    }
    

    Demo Hurray!

    Now what about the conditional part? You don't need it. If you want to assert that the colour is either green or yellow, just assert it.

    #define is_green(color) ((struct {static_assert(color==GREEN||color==YELLOW, "Bad color!"); int z;}){1}, color == GREEN)
    

    Demo

    Of course it will work only if the argument to the macro is a constant expression.