宏内的变量参数

时间:2017-12-06 12:47:25

标签: c variables macros arguments

我有两个函数foo1(a,b)& foo2(a,b,c)和宏

#define add(a,b) foo(a,b)

我需要重新定义宏来完成,

1.如果使用2个参数调用add(),则调用foo1

  1. 如果使用3个参数调用add(),则调用foo2
  2. 我是VA_ARGS选项的新手。我怎么能这样做

3 个答案:

答案 0 :(得分:3)

usual trick for counting arguments可能适用于此:

#define ADD_EXPAND(...) \
        ADD_EXPAND_(__VA_ARGS__, EXPAND_ADD_FUNCS())

#define ADD_EXPAND_(...) \
        EXPAND_ADD_SEL_FUNC(__VA_ARGS__)

#define EXPAND_ADD_SEL_FUNC(first_, second_, third_, func, ...) func

#define EXPAND_ADD_FUNCS() foo2, foo, dummy

#define add(...) ADD_EXPAND(__VA_ARGS__)(__VA_ARGS__)

一旦你翻过锅炉板,它基本上只需要将所有参数放在一行中,然后将函数标记放在它们之后,并查看哪个函数突出。这就是EXPAND_ADD_SEL_FUNC所做的。

你可以看到 live on coliru

但我会重申我们在评论中告诉你的内容。这可能是适当功能的低于标准的解决方案。我没有彻底测试过,所以很容易破损。使用风险由您自己承担。

答案 1 :(得分:3)

如果您只想区分两个功能,可以使用以下功能:

#define ADD(_1, _2, _3, X, ...) X
#define add(...) ADD(__VA_ARGS__, add3, add2, 0)(__VA_ARGS__)

辅助宏ADD总是选择第四个参数:

add(a, b)    --> ADD(a, b, add3, add2, 0)    --> add2
add(a, b, c) --> ADD(a, b, c, add3, add2, 0) --> add3

缺点是当你没有为函数提供两个或三个参数时,你会收到相当神秘的错误消息。

与可变功能相比,优势在于您可以获得类型安全性。例如,如果您的函数在double上运行,您仍然可以说add(1, 2)并且整数参数将转换为double s。并且可变参数函数需要关于实际参数数量的一些额外信息,因此这里不是可行的解决方案,除非您在函数中指定了加数的数量。

附录:我已更改了add宏,因此它没有将空的可变参数列表传递给ADD。有些编译器允许使用空列表,但它不是标准C。

答案 2 :(得分:2)

如果必须使用可变参数宏,那么这是一个技巧。

#define add(...) _Generic ( &(int[]){__VA_ARGS__}, \
                            int(*)[2]: add2,       \
                            int(*)[3]: add3) (__VA_ARGS__)
  • 让宏创建复合文字数组。此数组的大小取决于参数的数量。
  • 获取复合文字的地址,以获取数组指针类型。
  • _Generic检查你得到的类型,然后根据它调用正确的函数。

这是100%标准C,也是类型安全的。

演示:

#include <stdio.h>


#define add(...) _Generic ( &(int[]){__VA_ARGS__}, \
                            int(*)[2]: add2,       \
                            int(*)[3]: add3) (__VA_ARGS__)

int add2 (int a, int b);
int add3 (int a, int b, int c);

int main (void)
{
  printf("%d\n", add(1, 2));
  printf("%d\n", add(1, 2, 3));
//printf("%d\n", add(1, 2, 3, 4)); Compiler error for this.
}


int add2 (int a, int b)
{
  return a + b;
}

int add3 (int a, int b, int c)
{
  return a + b + c;
}