Variadic recursive preprocessor macros – is it possible

c-preprocessormacros

I've run into a little theoretical problem. In a piece of code I'm maintaining there's a set of macros like

#define MAX_OF_2(a, b)       (a) > (b) ? (a) : (b)
#define MAX_OF_3(a, b, c)    MAX_OF_2(MAX_OF_2(a, b), c)
#define MAX_OF_4(a, b, c, d) MAX_OF_2(MAX_OF_3(a, b, c), d)
...etc up to MAX_OF_8

What I'd like to do is replace them with something like this:

/* Base case #1, single input */
#define MAX_OF_N(x)      (x)

/* Base case #2, two inputs */
#define MAX_OF_N(x, y)   (x) > (y) ? (x) : (y)

/* Recursive definition, arbitrary number of inputs */
#define MAX_OF_N(x, ...) MAX_OF_N(x, MAX_OF_N(__VA_ARGS__))

…which, of course, is not valid preprocessor code.

Ignoring that this particular case should probably be solved using a function rather than a preprocessor macro, is it possible to define a variadic MAX_OF_N() macro?

Just for clarity, the end result should be a single macro that takes an arbitrary number of parameters and evaluates to the largest of them. I've got an odd feeling that this should be possible, but I'm not seeing how.

Best Answer

It's possible to write a macro that evaluates to the number of arguments it's called with. (I couldn't find a link to the place where I first saw it.) So you could write MAX_OF_N() that would work as you'd like, but you'd still need all the numbered macros up until some limit:

#define MAX_OF_1(a)         (a)         
#define MAX_OF_2(a,b)       max(a, b)

#define MAX_OF_3(a,...)    MAX_OF_2(a,MAX_OF_2(__VA_ARGS__))
#define MAX_OF_4(a,...)    MAX_OF_2(a,MAX_OF_3(__VA_ARGS__))
#define MAX_OF_5(a,...)    MAX_OF_2(a,MAX_OF_4(__VA_ARGS__))
...
#define MAX_OF_64(a,...)   MAX_OF_2(a,MAX_OF_63(__VA_ARGS__))

// NUM_ARGS(...) evaluates to the literal number of the passed-in arguments.
#define _NUM_ARGS2(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

#define _MAX_OF_N3(N, ...) MAX_OF_ ## N(__VA_ARGS__)
#define _MAX_OF_N2(N, ...) _MAX_OF_N3(N, __VA_ARGS__)
#define MAX_OF_N(...)      _MAX_OF_N2(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

Now MAX_OF_N(a,b,c,d,e) will evaluate to max(a, max(b, max(c, max(d, e)))). (I've tested on gcc 4.2.1.)

Note that it's critical that the base case (MAX_OF_2) doesn't repeat its arguments more than once in the expansion (which is why I put max in this example). Otherwise, you'd be doubling the length of the expansion for every level, so you can imagine what will happen with 64 arguments :)