Macro Expansion in C/C++ with __VA_ARGS__

I found these two pieces of code related to what is a varidic macro

1.The first example is used to achieve portability between the GNU C compiler and the Visual C Compiler, but I can't understand how this macro expands step by step

 MACRO_VA_ARGS(foo, bar, baz)

Is the inner or outer parenthesis evaluated first?

#define MACRO_WITH_3_PARAMS(p1, p2, p3) P1 = p1 | P2 = p2 | P3 = p3
#define PASS_ON(...) __VA_ARGS__

#define MACRO_VA_ARGS(...) PASS_ON(PASS_ON(MACRO_WITH_3_PARAMS)( __VA_ARGS__))
MACRO_VA_ARGS(foo, bar, baz)

All code for first example:

#define F_OR(i, a, b, s) for (int i=(a); (s)>0?i<(b):i>(b); i+=(s))
#define F_OR1(e) F_OR(i, 0, e, 1)
#define F_OR2(i, e) F_OR(i, 0, e, 1)
#define F_OR3(i, b, e) F_OR(i, b, e, 1)
#define F_OR4(i, b, e, s) F_OR(i, b, e, s)
#define GET5(a, b, c, d, e, ...) e
#define F_ORC(...) GET5(__VA_ARGS__, F_OR4, F_OR3, F_OR2, F_OR1)
#define FOR(...) F_ORC(__VA_ARGS__)(__VA_ARGS__)

2.The second code example I found on Github, I know that

#define GET5(a, b, c, d, e, ...) e

extracts 5th element, but I don't understand how these two macros expand:

#define F_ORC(...) GET5(__VA_ARGS__, F_OR4, F_OR3, F_OR2, F_OR1)
#define FOR(...) F_ORC(__VA_ARGS__)(__VA_ARGS__)

All code for second example:

 #define F_OR(i, a, b, s) for (int i=(a); (s)>0?i<(b):i>(b); i+=(s))
 #define F_OR1(e) F_OR(i, 0, e, 1)
 #define F_OR2(i, e) F_OR(i, 0, e, 1)
 #define F_OR3(i, b, e) F_OR(i, b, e, 1)
 #define F_OR4(i, b, e, s) F_OR(i, b, e, s)
 #define GET5(a, b, c, d, e, ...) e
 #define F_ORC(...) GET5(__VA_ARGS__, F_OR4, F_OR3, F_OR2, F_OR1)
 #define FOR(...) F_ORC(__VA_ARGS__)(__VA_ARGS__)

Thank you!

Upvotes: 2

Views: 551

Answers (1)

Hot_Pink_Spin
Hot_Pink_Spin

Reputation: 543

1.First one is pretty straight forward with where PASS_ON function is just to elaborate the macro usage(or to confuse).

Final expansion will be,

MACRO_VA_ARGS(foo, bar, baz)    =>      P1 = foo | P2 = bar | P3 = baz

Step-wise expansion will be,

#1

MACRO_VA_ARGS(foo, bar, baz)    =>      PASS_ON(PASS_ON(MACRO_WITH_3_PARAMS)( foo, bar, baz))

#2

PASS_ON(PASS_ON(MACRO_WITH_3_PARAMS)( foo, bar, baz))   =>      PASS_ON(MACRO_WITH_3_PARAMS( foo, bar, baz))

#3

PASS_ON(MACRO_WITH_3_PARAMS( foo, bar, baz))    =>      PASS_ON(P1 = foo | P2 = bar | P3 = baz)

#4

PASS_ON(P1 = foo | P2 = bar | P3 = baz)         =>      P1 = foo | P2 = bar | P3 = baz

2.Second one quite interesting as it preserves argument for the GET5, which extracts the 5th element which is indeed F_OR1 in every case.If we call FOR(5),

Final expansion will be,

FOR(5)  =>      for (int i=(0); (1)>0?i<(5):i>(5); i+=(1))

Step-wise expansion will be,

#1

FOR(5)  =>      F_ORC(5)(5)

#2

F_ORC(5)(5)     =>      GET5(5, F_OR4, F_OR3, F_OR2, F_OR1)(5)

#3

GET5(5, F_OR4, F_OR3, F_OR2, F_OR1)(5)  =>      F_OR1(5)

#4

F_OR1(5)        =>      F_OR(i, 0, 5, 1)

#5

F_OR(i, 0, 5, 1)        =>      for (int i=(0); (1)>0?i<(5):i>(5); i+=(1))

Upvotes: 1

Related Questions