views:

1970

answers:

5

Simple question for which I could not find answer on the net. In variadic argument macros, how to find the number of arguments? I am okay with boost preprocessor, if it has the solution.

If it makes a difference, I am trying to convert variable number of macro arguments to boost preprocessor sequence, list, or array for further reprocessing.

+7  A: 

This is actually compiler dependent, and not supported by any standard.

Here however you have a macro implementation that does the count.

Kornel Kisielewicz
perfect, thanks
aaa
Very devious - but effective.
Jonathan Leffler
+1  A: 

Neither the C nor the C++ preprocessor provides a way to find out the number of arguments in a variadic argument list to a macro. Indeed, the C++98 standard uses the C89 preprocessor and does not support variadic arguments to macros at all.

Your question says

I am OK with Boost preprocessor; it has the solution

So if the Boost preprocessor has the solution, why are you asking the question? Or did you mean:

I am OK with Boost preprocessor if it has the solution.

Jonathan Leffler
Maybe he prefers not to use the boost preprocessor, but he will if he has no other choice
Andreas Bonini
sorry, meant to say if it, i edited the question
aaa
+1  A: 

I usually use this macro to find a number of params:

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))

Full example:

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define SUM(...)  (sum(NUMARGS(__VA_ARGS__), __VA_ARGS__))

void sum(int numargs, ...);

int main(int argc, char *argv[]) {

    SUM(1);
    SUM(1, 2);
    SUM(1, 2, 3);
    SUM(1, 2, 3, 4);

    return 1;
}

void sum(int numargs, ...) {
    int     total = 0;
    va_list ap;

    printf("sum() called with %d params:", numargs);
    va_start(ap, numargs);
    while (numargs--)
        total += va_arg(ap, int);
    va_end(ap);

    printf(" %d\n", total);

    return;
}

It is completely valid C99 code. It has one drawback, though - you cannot invoke the macro SUM() without params, but GCC has a solution to it - see here.

So in case of GCC you need to define macros like this:

#define       NUMARGS(...)  (sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1)
#define       SUM(...)  sum(NUMARGS(__VA_ARGS__), ##__VA_ARGS__)

and it will work even with empty parameter list

qrdl
UM, it won't work for the OP, he needs the size for BOOST_PP which runs on compile time.
Kornel Kisielewicz
Clever! Does it also work when `sizeof(int) != sizeof(void *)` ?
Adam Liss
@Kornel Like any macro, it is evaluated at compile time. I have no idea about Boost, but anyway Boost isn't needed.
qrdl
@Adam Because I cast `{__VA_ARGS__}` to `int[]`, it is just `int[]`, regardless of actual content of `__VA_ARGS__`
qrdl
@qrdl, so I can write `SUM( myfunc(2), myarr[10], 2+3 )`?
Kornel Kisielewicz
@Kornel Of course you can, and it works for both C99 and GCC. Why don't you just try it yourself?
qrdl
A: 

Although there's no easy solution for the general case in which your function receives an arbitrary number of arguments of arbitrary types, the problem becomes easier if you follow the convention of using the first argument to give yourself clues.

This is how functions like printf() work:  the first argument (the format string) provides enough information to determine the number and types of the successive arguments. For example:

printf("This call to %*s requires %d argument%c\n",
    length, string,
    num,
    num == 1  ?  ' ' : 's');

%*s requires an integer argument and a pointer.
%d   requires an integer.
%c   requires a character.

So the format string completely specifies the remaining 4 arguments.

Adam Liss
+1  A: 

You can use this GNU extension:

#define macro(format, arguments...) fprintf(stderr, format, ## arguments)

Just remember - it only works with GNU compiler.