问题
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