C宏:如何将另一个宏映射到可变参数? [英] C Macros: How to map another macro to variadic arguments?

查看:430
本文介绍了C宏:如何将另一个宏映射到可变参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'd like to know how to apply a unary function (or another macro) to variadic arguments of a macro, like

int f(int a);

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

可展开

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

请注意,参数数量未知.

Note that the number of arguments is unknown.

推荐答案

下面的代码适用于您要求的内容,最多包含1024个参数,并且没有使用了boost等其他内容.它定义了一个EVAL(...)和一个MAP(m, first, ...)宏来进行递归,并为每次迭代使用带有下一个参数first的宏m.

The code below is working for what you've asked for with up to 1024 arguments and without using additional stuff like boost. It defines an EVAL(...) and also a MAP(m, first, ...) macro to do recursion and to use for each iteration the macro m with the next parameter first.

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

With the use of that, your apply(...) looks like: #define apply(...) EVAL(MAP(apply_, __VA_ARGS__)).

它主要是从 C预处理器魔术复制而来.那里的解释也很棒.您也可以在 git存储库,实际代码中也有很多说明.它是可变参数的,因此它需要您想要的参数数量.

It is mostly copied from C Pre-Processor Magic. It is also great explained there. You can also download these helper macros like EVAL(...) at this git repository, there are also a lot of explanation in the actual code. It is variadic so it takes the number of arguments you want.

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

But I changed the FIRST and the SECOND macro as it uses a Gnu extension like it is in the source I've copied it from. This is said in the comments below by @HWalters:

具体地说,是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__))


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


To test macro expansion it is useful to use gcc with the command line argument -E:

$ gcc -E srcFile.c

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

because your're getting concrete error messages and understand what's going on.

这篇关于C宏:如何将另一个宏映射到可变参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆