简体   繁体   中英

C macro, wrong argument number returned

I have following macros:

#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__)

These are my test cases:

// 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);

Could please someone explain to me what I'm doing wrong for the case with only one argument, #define SOME(x) int x ??

Compile it with gcc -E macro.c -o macro.lol , gives result:

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

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


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

The problem is that when you pass two arguments to FOR_EACH (just the what and x ), the __VA_ARGS__ expands to nothing, and you have a trailing comma in the call to FOR_EACH_NARG , so it expands to 2 and therefore expands FOR_EACH_2 .

You want to get rid of that trailing comma. You can do that by either using the non-standard extension of using ##__VA_ARGS__ instead of __VA_ARGS__ , which removes the comma before it only if __VA_ARGS__ is empty. For a more standards-compliant version, you can combine the x and __VA_ARGS__ into a single parameter:

#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__)

You should have seen some warning from your compiler, that you failed to tell us about.

My guess would be that your macro here

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

is wrong because it never sees a __VA_ARGS__ part. I see two ways of healing that

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

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

Another thing that could hurt you with such macros is the different counting of argument numbers than you are used to with C.

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

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

If you are doing this for learning the preprocessor, this is fine :) if you really what a generic solution for this kind of problems you could have a look into Boost (but this is mainly C++) and P99

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM