采用0或1个参数的Variadic宏?

时间:2012-09-30 15:38:28

标签: objective-c c c-preprocessor

如何编写可以采用1或0参数的可变参数宏。即像这样的东西:

GREET()         // returns @"Hello World"
GREET(@"John")  // returns @"Hello John"

4 个答案:

答案 0 :(得分:9)

这很简单,你有这样的东西:

#define __NARGS(unused, _1, _2, _3, _4, _5, VAL, ...) VAL
#define NARGS(...) __NARGS(unused, ## __VA_ARGS__, 5, 4, 3, 2, 1, 0)

#define __GREET(ARGC, ARGS...) GREET_ ## ARGC (ARGS)
#define _GREET(ARGC, ARGS...) __GREET(ARGC, ARGS)
#define GREET(...) _GREET(NARGS(__VA_ARGS__), __VA_ARGS__)

#define GREET_0(...) @"Hello World!"
#define GREET_1(ARG, ...) @"Hello, " ARG // strings are auto-concatenated in objc

int main()
{
    NSLog(@"%@", GREET());
    NSLog(@"%@", GREET(@"John"));
}

<强>输出:

2012-09-30 11:56:48.478 TestProj[51823:303] Hello World!
2012-09-30 11:56:48.480 TestProj[51823:303] Hello, John

现在,这非常复杂,但假设您从基本层面了解预处理器的工作原理,那么您应该能够理解正在发生的事情。

答案 1 :(得分:4)

我不知道这是否适用于目标C,但对于C99和C11,您可以使用具有元宏P99_IF_EMPTY的{​​{3}}

#define GREET(...) P99_IF_EMPTY(__VA_ARGS__)("Hello World")("Hello " __VA_ARGS__)

答案 2 :(得分:2)

执行此操作的一种好方法是使用重复元素构建数据结构,例如:

union greet_arg {
  char *string;
};
struct greet_args {
  union greet_arg *arg[2];
};
void greet_function(struct greet_args *x);

您的宏可以像这样实现:

#define GREET(x...)  greet_function(&(struct greet_args){0, x})

现在这样做的原因是,如果你打电话给GREET("foo"),那么你得到:

greet_function(&(struct greet_args){0, "foo"});

如果你打电话给GREET(),你会得到:

greet_function(&(struct greet_args){0, });

仍然有效; “0”只是填充数组的其余部分。

您的greet_function()然后只需检查x->arg[1]

答案 3 :(得分:1)

宏具有可变参数,或者它具有固定数量的参数。要获得所需的结果,请声明2个宏,一个带0个参数,一个带1个参数。