C 宏 : How to map another macro to variadic arguments?

标签 c macros

我想知道如何将一元函数(或另一个宏)应用于宏的可变参数,例如

int f(int a);

#define apply(args...) <the magic>
apply(a, b, c)

展开

f(a)
f(b)
f(c)

请注意,参数的数量是未知的。

最佳答案

下面的代码使用最多 1024 个参数来满足您的要求,并且没有使用额外的东西,比如 boost。它定义了一个 EVAL(...) 和一个 MAP(m, first, ...) 宏来进行递归并在每次迭代中使用宏 m 与下一个参数 first

使用它,您的 apply(...) 看起来像:#define apply(...) EVAL(MAP(apply_, __VA_ARGS__)) .

大部分抄自C Pre-Processor Magic .那里也有很好的解释。您还可以在此 git repository 下载这些辅助宏,例如 EVAL(...) ,实际代码中也有很多解释。它是可变的,所以它需要你想要的参数数量。

但我更改了 FIRSTSECOND 宏,因为它使用 Gnu 扩展,就像我从中复制它的源代码一样。这是@ HWalters 在下面的评论中所说的。 :

Specifically, 6.10.3p4: "Otherwise [the identifier-list ends in a ...] there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...)".

主要功能部分:

int main()
{
   int a, b, c;
   apply(a, b, c) /* Expands to: f(a); f(b); f(c); */

   return 0;
}

宏定义:

#define FIRST_(a, ...) a
#define SECOND_(a, b, ...) b

#define FIRST(...) FIRST_(__VA_ARGS__,)
#define SECOND(...) SECOND_(__VA_ARGS__,)

#define EMPTY()

#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__

#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()

#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1

#define CAT(a,b) a ## b

#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()

#define BOOL(x) NOT(NOT(x))

#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)

#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...)             _IF_0_ELSE

#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__

#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0

#define MAP(m, first, ...)           \
  m(first)                           \
  IF_ELSE(HAS_ARGS(__VA_ARGS__))(    \
    DEFER2(_MAP)()(m, __VA_ARGS__)   \
  )(                                 \
    /* Do nothing, just terminate */ \
  )
#define _MAP() MAP

#define apply_(x) f(x);
#define apply(...) EVAL(MAP(apply_, __VA_ARGS__))

要测试宏扩展,将 gcc 与命令行参数 -E 一起使用是很有用的:

$ gcc -E srcFile.c

因为您收到了具体的错误消息并了解发生了什么。

关于C 宏 : How to map another macro to variadic arguments?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45585903/

相关文章:

c - Visual Studio 2013 : C Application on any Windows version

c - 删除矩阵中相同的行

c - 下面的c 宏声明是什么意思?

c - 当IP指向0时调试指令指针

c - Valgrind 无法在 MacOS Mojave 上运行?与 conda 一起安装

java - 使用数组的 JNI 任务

c - 为什么在 foreach 宏中使用 "(array) + count"?

visual-studio-2005 - 在哪里可以找到 Visual Studio 宏示例?

macros - (mymacro arg) 和 (eval (myfunc (quote arg))) 有什么区别

ios - 是否可以编译由于 Xcode 中的编译器预处理器宏而更改的文件?