你将如何编写一个可以接受 1 个或 0 个参数的可变参数宏。即是这样的:
GREET() // returns @"Hello World"
GREET(@"John") // returns @"Hello John"
你将如何编写一个可以接受 1 个或 0 个参数的可变参数宏。即是这样的:
GREET() // returns @"Hello World"
GREET(@"John") // returns @"Hello John"
这很简单,你有这样的东西:
#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] 你好世界! 2012-09-30 11:56:48.480 TestProj[51823:303] 你好,约翰
现在,这相当复杂,但假设您基本了解预处理器的工作原理,您应该能够很好地了解正在发生的事情。
我不知道这是否适用于目标 C,但对于 C99 和 C11,您可以使用具有元宏的P99P99_IF_EMPTY
#define GREET(...) P99_IF_EMPTY(__VA_ARGS__)("Hello World")("Hello " __VA_ARGS__)
一个很好的方法是构建一个带有重复元素的数据结构,例如:
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]
.
宏要么具有可变参数,要么具有固定数量的参数。要获得所需的结果,请声明 2 个宏,一个带有 0 个参数,一个带有 1 个参数。