如何编写可以采用1或0参数的可变参数宏。即像这样的东西:
GREET() // returns @"Hello World"
GREET(@"John") // returns @"Hello John"
答案 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个参数。