3

你将如何编写一个可以接受 1 个或 0 个参数的可变参数宏。即是这样的:

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

4 回答 4

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] 你好世界!
2012-09-30 11:56:48.480 TestProj[51823:303] 你好,约翰

现在,这相当复杂,但假设您基本了解预处理器的工作原理,您应该能够很好地了解正在发生的事情。

于 2012-09-30T15:57:31.177 回答
4

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

#define GREET(...) P99_IF_EMPTY(__VA_ARGS__)("Hello World")("Hello " __VA_ARGS__)
于 2012-09-30T17:17:23.240 回答
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].

于 2012-09-30T15:53:42.387 回答
1

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

于 2012-09-30T15:46:28.210 回答