C 中的大小写可变宏
Case variadic macro in C
我有 2 个包装器宏用于断言函数输入参数:
/**
* @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_; \
前者用于返回void的函数,后者用于返回非void的函数。我想知道在 C11(或更早版本)中是否有一种机制允许人们只使用带有可变参数数量的单个宏。根据提供给宏的参数数量(1 或 2),将编译 return
或 return ret_
。
你可以这样做:
#define UTIL_ASSERT(x_, ...) \
assert_param(x_); \
if (!x_) \
return __VA_ARGS__;
但请记住,您不能保证此可变参数宏中只有 1 个参数,因此您需要正确使用它。
更新:
感谢 this 线程,我找到了更好的方法:
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);
}
这个比上一个好很多,因为它以某种方式验证了参数的数量。
有一种方法可以用标准 C 来做这些事情。首先你有一个核心宏来完成这两种情况的工作
#define ASSERT0(X, RET, ...)
/* put your stuff here that only uses X and RET, and ignores the ... */
如您所见,它接收三个或更多参数。你必须安排 RET
只是你需要这个的空标记。
现在你可以把它包裹起来
#define ASSERT1(...) ASSERT0(__VA_ARGS__)
这确保可能位于单个参数内的逗号将被视为 ASSERT0
.
的参数分隔符
然后用户级宏就可以
#define MY_ASSERT(...) ASSERT1(__VA_ARGS__, ,)
这确保如果您只将它与一个参数一起使用,ASSERT0
下面将看到一个空的第二个参数。如果你用两个参数调用它,ASSERT0
将只看到这些。
您还应该考虑将内部宏包装在 do { ... } while(0)
中。否则,您可能会遇到 "dangling else
" 问题并使用户对其他句法效果感到困惑。
我有 2 个包装器宏用于断言函数输入参数:
/**
* @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_; \
前者用于返回void的函数,后者用于返回非void的函数。我想知道在 C11(或更早版本)中是否有一种机制允许人们只使用带有可变参数数量的单个宏。根据提供给宏的参数数量(1 或 2),将编译 return
或 return ret_
。
你可以这样做:
#define UTIL_ASSERT(x_, ...) \
assert_param(x_); \
if (!x_) \
return __VA_ARGS__;
但请记住,您不能保证此可变参数宏中只有 1 个参数,因此您需要正确使用它。
更新: 感谢 this 线程,我找到了更好的方法:
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);
}
这个比上一个好很多,因为它以某种方式验证了参数的数量。
有一种方法可以用标准 C 来做这些事情。首先你有一个核心宏来完成这两种情况的工作
#define ASSERT0(X, RET, ...)
/* put your stuff here that only uses X and RET, and ignores the ... */
如您所见,它接收三个或更多参数。你必须安排 RET
只是你需要这个的空标记。
现在你可以把它包裹起来
#define ASSERT1(...) ASSERT0(__VA_ARGS__)
这确保可能位于单个参数内的逗号将被视为 ASSERT0
.
然后用户级宏就可以
#define MY_ASSERT(...) ASSERT1(__VA_ARGS__, ,)
这确保如果您只将它与一个参数一起使用,ASSERT0
下面将看到一个空的第二个参数。如果你用两个参数调用它,ASSERT0
将只看到这些。
您还应该考虑将内部宏包装在 do { ... } while(0)
中。否则,您可能会遇到 "dangling else
" 问题并使用户对其他句法效果感到困惑。