C宏:如何将另一个宏映射到可变参数?

C宏:如何将另一个宏映射到可变参数?,c,macros,C,Macros,我想知道如何将一元函数(或另一个宏)应用于宏的可变参数,如 int f(int a); #define apply(args...) <the magic> apply(a, b, c) 请注意,参数的数量是未知的。除非您使用这样可怕的技巧和黑客,否则我是不可能的 正如我看到的,它调用了相同的函数,因此参数的类型是已知的-为什么不使用stdarg。下面的代码使用了1024个参数,而不使用像boost这样的附加功能。它定义了一个EVAL(…)和一个MAP(m,first,…)宏来

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

int f(int a);

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

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

除非您使用这样可怕的技巧和黑客,否则我是不可能的


正如我看到的,它调用了相同的函数,因此参数的类型是已知的-为什么不使用
stdarg

下面的代码使用了1024个参数,而不使用像boost这样的附加功能。它定义了一个
EVAL(…)
和一个
MAP(m,first,…)
宏来执行递归,并在每次迭代中使用宏
m
和下一个参数
first

使用该函数后,您的
apply(…)
看起来像:
\define apply(…)EVAL(MAP(apply,\uu VA_ARGS)

这本书大部分是抄袭的。这也是伟大的解释。您还可以下载这些帮助程序宏,如
EVAL(…)
,在这里,实际代码中也有很多解释。它是可变的,所以它需要你想要的参数数量

但是我更改了
第一个
第二个
宏,因为它使用Gnu扩展,就像我从源代码中复制它一样。以下评论中有@这样说:

具体而言,6.10.3p4:“否则[标识符列表以…]结尾]调用中的参数应多于宏定义中的参数(不包括…)

主要功能部件:

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__))
宏定义:

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中,如果你向它抛出足够多难看的宏,一切都是可能的。例如,可以使用一个丑陋的函数,如宏:

#include <stdio.h>

int f (int a)
{
  printf("%d\n", a);
}

#define SIZEOF(arr) (sizeof(arr) / sizeof(*arr))

#define apply(...)                    \
{                                     \
  int arr[] = {__VA_ARGS__};          \
  for(size_t i=0; i<SIZEOF(arr); i++) \
  {                                   \
    f(arr[i]);                        \
  }                                   \
}

int main (void)
{
  apply(1, 2, 3);
}

FIRST
如图所示依赖于非标准gnu扩展。根据标准,此实现需要两个参数;使用它需要
首先
接受一个参数
#define FIRST(…)FIRST(uu VA_ARGS uuu,)
#define FIRST_ux(…)x
是一个修复程序。与
SECOND
类似。此外,
HAS_ARGS
充其量只是一个名称不好的词;如果没有参数传递,它就不是真正的测试。相反,它是在测试它的第一个参数是否为空。@HWalters:谢谢!正如我所说,它主要是从我在回答中提到的来源复制的。我不明白为什么
首先
不适用于所有编译器/预处理器,为什么您的版本可以解决这个问题?“我的版本”只是抛出了
\uuu VA\u ARGS\uuu
为什么这是gnu扩展?具体来说,6.10.3p4:“否则[标识符列表以…]结尾]调用中的参数应多于宏定义中的参数(不包括…)。(我知道你要求一个链接,但文本中有一条评论)<因此,代码>第一(a,…)至少需要两个参数。接受1是与其逗号省略功能相关的gnu扩展。@HWalters:非常感谢您获得并更改了它@赵雄翠:还有一个小错误,扩展到:
f(a),f(b),f(c),前面中间有逗号。现在扩展工作了,它扩展到:
f(a);f(b);f(c)
。在定义apply时可以使用
do{…},而(0)
。@fzyzcjy取决于上下文。如果目标是生成高质量的C代码,那么非高质量的C代码不使用
If()x();else
不带大括号
{}
并且允许这样的代码是do while(0)的唯一目的。如果目标是创建一些可移植的lib,这些lib可以被具有不同代码质量标准的所有用户使用,那么应该使用do-while(0)。谢谢!我很少听说这种事explanation@fzyzcjy这就是为什么MISRA-C放弃使用do while(0)的要求的原因。在旧版本的MISRA中,函数类宏是必需的,但在最新版本中,他们放弃了该规则,因为MISRA-C已经要求在所有控制和循环语句之后必须始终使用大括号。