Case variadic macro in C

拈花ヽ惹草 提交于 2020-01-05 05:18:50

问题


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.


回答1:


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.




回答2:


There is a way to do such things that are standard C. First you have a core macro that does the job for both cases

#define ASSERT0(X, RET, ...) 
   /* put your stuff here that only uses X and RET, and ignores the ... */

As you can see this receives three arguments or more. And you'd have to arrange that RET is just the empty token for the case that you need this.

Now you can put a wrapper around that

#define ASSERT1(...) ASSERT0(__VA_ARGS__)

This assures that commas that may be inside individual arguments will be seen as argument separators for ASSERT0.

The user level macro can then be

#define MY_ASSERT(...) ASSERT1(__VA_ARGS__, ,)

This ensures that if you use it with only one argument ASSERT0 down below will see an empty second argument. If you call it with two arguments, ASSERT0 will just see these.

Also you should consider to wrap your inner macro in do { ... } while(0). Otherwise you can have a "dangling else" problem and confuse users with other syntactic effects.



来源:https://stackoverflow.com/questions/55075117/case-variadic-macro-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!