Reputation: 135
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
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