Search code examples
cmacrosc11variadic-macros

Case variadic macro in C


I have 2 wrapper macros for asserting function input parameters:

/**
 * @brief   An assert wrapper with no value return in case assert fails.
 * @param   x_: value to test for being non zero.
 */
#define UTIL_ASSERT_VOID(x_)                                                \
    assert_param(x_);                                                       \
    if (!x_)                                                                \
        return;                                                             \

/**
 * @brief   An assert wrapper with a value return in case assert fails.
 * @param   x_: value to test for being non zero.
 */
#define UTIL_ASSERT_VAL(x_, ret_)                                           \
    assert_param(x_);                                                       \
    if (!x_)                                                                \
        return ret_;                                                        \

The former is used in functions returning void, while the latter in functions returning non-void. I was wondering either in C11 (or earlier) there is a mechanism allowing one to use only a single macro with variadic parameters amount. Depending on how many parameters are provided to the macro (1 or 2), a return or return ret_ would be compiled.


Solution

  • You can do it like this:

    #define UTIL_ASSERT(x_, ...)                                                \
        assert_param(x_);                                                       \
        if (!x_)                                                                \
            return __VA_ARGS__;
    

    But remember, you cannot guarantee just 1 parameter in this variadic macro, so you need to use it correctly.

    Update: Thanks to this thread, I came to better approach:

    void assert_param(int x);
    
    #define UTIL_ASSERT_1(x_)   do { assert_param(x_); if (!x_) return; } while(0)
    
    #define UTIL_ASSERT_2(x_, ret_)   do { assert_param(x_); if (!x_) return ret_; } while(0)     
    
    #define GET_MACRO(_1,_2,NAME,...) NAME
    #define UTIL_ASSERT(...) GET_MACRO(__VA_ARGS__, UTIL_ASSERT_2, UTIL_ASSERT_1)(__VA_ARGS__)
    
    
    int foo() {
         UTIL_ASSERT(0,1);
    }
    
    void doo() {
         UTIL_ASSERT(0);
    }
    

    This one is much better than previous one, because it somehow validates number of parameters.