C宏,返回错误的参数号

时间:2012-11-06 15:31:26

标签: c c-preprocessor

我有以下宏:

#define CONCATENATE(arg1, arg2)  arg1##arg2

#define FOR_EACH_1(what, x, ...) what(x)
#define FOR_EACH_2(what, x, ...) what(x) FOR_EACH_1(what, __VA_ARGS__)
#define FOR_EACH_3(what, x, ...) what(x) FOR_EACH_2(what, __VA_ARGS__)
#define FOR_EACH_4(what, x, ...) what(x) FOR_EACH_3(what, __VA_ARGS__)
#define FOR_EACH_5(what, x, ...) what(x) FOR_EACH_4(what, __VA_ARGS__)
#define FOR_EACH_6(what, x, ...) what(x) FOR_EACH_5(what, __VA_ARGS__)
#define FOR_EACH_7(what, x, ...) what(x) FOR_EACH_6(what, __VA_ARGS__)
#define FOR_EACH_8(what, x, ...) what(x) FOR_EACH_7(what, __VA_ARGS__)

#define FOR_EACH_NARG(...) FOR_EACH_NARG_(__VA_ARGS__, FOR_EACH_RSEQ_N())
#define FOR_EACH_NARG_(...) FOR_EACH_ARG_N(__VA_ARGS__)
#define FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0

#define FOR_EACH_(N, what, x, ...) CONCATENATE(FOR_EACH_, N)(what, x, __VA_ARGS__)
#define FOR_EACH(what, x, ...) FOR_EACH_(FOR_EACH_NARG(x, __VA_ARGS__), what, x, __VA_ARGS__)

这些是我的测试用例:

// does not work as intended (with one argument)
#define SOME(x) int x;
FOR_EACH(SOME, y)

// fine with 2 and more
FOR_EACH(SOME, y1, y2);
FOR_EACH(SOME, y3, y4, y5, y6);

// works fine even for one argument
#define ONLY(x) x
int FOR_EACH(ONLY, x);

可以请某人向我解释一下我只做了一个论证,#define SOME(x) int x ??

gcc -E macro.c -o macro.lol编译,给出结果:

int y; int ;  /* <-- that's wrong, why??? */

int y1; int y2;;
int y3; int y4; int y5; int y6;;


int x ;       /* <-- works as supposed */

2 个答案:

答案 0 :(得分:4)

问题在于,当您将两个参数传递给FOR_EACH(仅whatx)时,__VA_ARGS__会扩展为空,并且您有一个尾随逗号在调用FOR_EACH_NARG时,它会扩展为2,因此展开FOR_EACH_2

你想摆脱那个尾随的逗号。您可以使用##__VA_ARGS__使用__VA_ARGS__而不是__VA_ARGS__来执行此操作,仅当x为空时才会删除之前的逗号。要获得更符合标准的版本,您可以将__VA_ARGS__#define FOR_EACH_(N, what, ...) CONCATENATE(FOR_EACH_, N)(what, __VA_ARGS__) #define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__) 合并为一个参数:

{{1}}

答案 1 :(得分:1)

您应该看到编译器发出一些警告,但您没有告诉我们。

我的猜测是你的宏在这里

#define FOR_EACH_1(what, x, ...) what(x)

是错误的,因为它从未见过__VA_ARGS__部分。我看到两种治疗方法

#define FOR_EACH_1(what, ...) what(__VA_ARGS__)

#define FOR_EACH_1(what, x) what(x)

使用此类宏可能会对您造成伤害的另一个因素是参数编号的计数与您习惯使用的C不同。

#define MUCH(...)
#define NONE()

NONE   //<- this is considered receiving no argument
MUCH   //<- this receives one argument, the empty token list

如果你这样做是为了学习预处理器,那很好:)如果你真的是针对这类问题的通用解决方案你可以看看Boost(但这主要是C ++)和P99