C中的案例可变宏

问题描述 投票:0回答:2

我有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)的参数数量,将编译returnreturn ret_

c macros c11 variadic-macros
2个回答
3
投票

你可以这样做:

#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);
}

这个比前一个要好得多,因为它以某种方式验证了参数的数量。


2
投票

有一种方法可以做这些标准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)中。否则你可能会遇到“悬空else”问题,并将用户与其他句法效果混淆。

© www.soinside.com 2019 - 2024. All rights reserved.