C, invalid argument number returned

I have the 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); 

Can 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 to get the result:

 int y; int ; /* <-- that wrong, why??? */ int y1; int y2;; int y3; int y4; int y5; int y6;; int x ; /* <-- works as supposed */ 
+4
source share
2 answers

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

You want to get rid of this trailing comma. This can be done either by using a custom extension using ##__VA_ARGS__ instead of __VA_ARGS__ , which removes the comma in front of it only if __VA_ARGS__ empty. For a more standard version, you can combine x and __VA_ARGS__ into one 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__) 
+4
source

You should have seen a warning from your compiler that you did not tell us about.

I assume your macro is here

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

incorrect because he never sees the __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 can hurt you with such macros is a different calculation of the argument numbers than you are used to C.

 #define MUCH(...) #define NONE() NONE //<- this is considered receiving no argument MUCH //<- this receives one argument, the empty token list 

If you do this to study the preprocessor, that’s fine :) If you really imagine what a general solution for these kinds of problems you could study in Boost (but it is mainly C ++) and P99

+1
source

Source: https://habr.com/ru/post/1444392/


All Articles