Christof Warlich <cw******@alcatel-lucent.dewrote:
Hi,
is there any way to access individual elements in the body
of a variadic macro? I only found __VA_ARGS__, which always
expands to the complete list.
So, using Laurent's solution you can do lots of interesting things. For
instance, you can overload functions or macros:
#define foreach2(p, a) \
for (typeof(&(a)[0]) p = (a); p - (a) < lengthof(a); p++)
#define foreach3(p, a, n) \
for (typeof(&(a)[0]) p = (a); p - (a) < (n); p++)
#define foreach_(N, ...) PASTE(foreach, N)(__VA_ARGS__)
#define foreach(...) foreach_(PP_NARG(__VA_ARGS__), __VA_ARGS__)
That technique has proven very useful. Another interesting trick is to peek
into __VA_ARGS__. That requires some indirection, and extending calls with
dummy arguments. Here's something along those lines which I wrote this past
weekend; very simple. The '3' is the default value, which can be overridden
by the caller merely providing a second argument, shifting the default
argument into the ether. (Visual Studio doesn't support much of C99, but
2005 supports __VA_ARGS__; but don't quote me, because I almost always use
Mingw).
/*
* Prefetching
*/
#if __GNUC__ >= 3
#define prefetch_((w), (p), (l), ...) __builtin_prefetch((p), (w), (l))
#define prefetch(...) prefetch_(0, __VA_ARGS__, 3)
#define prefetchw(...) prefetch_(1, __VA_ARGS__, 3)
#elif _MSC_VER >= 1400
#include <winnt.h>
#define prefetch_((p), (l), ...) PreFetchCacheLine((l), (p))
#define prefetch(...) prefetch_(__VA_ARGS__, 3)
#define prefetchw(...) prefetch_(__VA_ARGS__, 3)
#else
#define prefetch(...)
#define prefetchw(...)
#endif
Following below is one of my attempts to combine that with PP_NARG to get
something more generic and reuseable. The result is PP_MAP, which is at the
end. I've used it to prefix arguments in a DNS library, so callers can do
things like
dns_lookup(dnsctx, a, aaaa, mx)
which using
#define dns_rr_prefix(type) dns_rr_##type
#define dns_lookup(dnsctx, ...) \
dns_lookup((dnsctx), PP_NARG(__VA_ARGS__), (int[]) { \
PP_MAP(dns_rr_prefix, __VA_ARGS__) \
})
gets turned into
dns_lookup(dnsctx, 3, (int[]){ dns_rr_a, dns_rr_aaaa, dns_rr_mx })
Actually, I do something a little different by using static inline
functions, so I can turn types into a 64-bit unsigned integral bitmap w/
overflow (types 62) copied into a compound literal variable-length array.
GCC -O2 can turn all of that into constants. Probably overkill for a DNS
library, but at the very least it improves the semantics of the user API
(and I always like to play around w/ loop elimination strategies).
The semantics of PP_MAP leaves something to be desired. It's more an
experiment. Laurent's PP_NARG, on the other hand, is close to perfection as
far as reusable macros go.
/*
* Select leading N items from list.
*/
#define PP_ARGV(N, ...) PASTE(PP_ARGV, N)(__VA_ARGS__)
#define PP_ARGV1(_00,...) \
_00
#define PP_ARGV2(_00,_01,...) \
_00,_01
#define PP_ARGV3(_00,_01,_02,...) \
_00,_01,_02
#define PP_ARGV4(_00,_01,_02,_03,...) \
_00,_01,_02,_03
#define PP_ARGV5(_00,_01,_02,_03,_04,...) \
_00,_01,_02,_03,_04
#define PP_ARGV6(_00,_01,_02,_03,_04,_05,...) \
_00,_01,_02,_03,_04,_05
#define PP_ARGV7(_00,_01,_02,_03,_04,_05,_06,...) \
_00,_01,_02,_03,_04,_05,_06
#define PP_ARGV8(_00,_01,_02,_03,_04,_05,_06,_07,...) \
_00,_01,_02,_03,_04,_05,_06,_07
#define PP_ARGV9(_00,_01,_02,_03,_04,_05,_06,_07,_08,...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08
#define PP_ARGV10(_00,_01,_02,_03,_04,_05,_06,_07,_08,_09, ...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08,_09
#define PP_ARGV11(_00,_01,_02,_03,_04,_05,_06,_07,_08,_09, _0a,...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08,_09,_0a
#define PP_ARGV12(_00,_01,_02,_03,_04,_05,_06,_07,_08,_09, _0a,_0b,...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08,_09,_0a,_0b
#define PP_ARGV13(_00,_01,_02,_03,_04,_05,_06,_07,_08,_09, _0a,_0b,_0c,...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08,_09,_0a,_0b,_0 c
#define PP_ARGV14(_00,_01,_02,_03,_04,_05,_06,_07,_08,_09, _0a,_0b,_0c,_0d,...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08,_09,_0a,_0b,_0 c,_0d
#define PP_ARGV15(_00,_01,_02,_03,_04,_05,_06,_07,_08,_09, _0a,_0b,_0c,_0d,_0e,...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08,_09,_0a,_0b,_0 c,_0d,_0e
#define PP_ARGV16(_00,_01,_02,_03,_04,_05,_06,_07,_08,_09, _0a,_0b,_0c,_0d,_0e,_0f,...) \
_00,_01,_02,_03,_04,_05,_06,_07,_08,_09,_0a,_0b,_0 c,_0d,_0e,_0f
/*
* Apply function-like macro F to each item in argument list.
*/
#define PP_MAP16(F,_00,_01,_02,_03,_04,_05,_06,_07,_08,_09 ,_0a,_0b,_0c,_0d,_0e,_0f,...) \
F(_00),F(_01),F(_02),F(_03),F(_04),F(_05),F(_06),F (_07), \
F(_08),F(_09),F(_0a),F(_0b),F(_0c),F(_0d),F(_0e),F (_0f)
#define PP_MAP_(F,...) PP_MAP16(F,__VA_ARGS__)
#define PP_MAP(F,...) PP_ARGV(PP_NARG(__VA_ARGS__),PP_MAP_(F,__VA_ARGS__ ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))