Counting Arguments in C99

S

Shao Miller

Does anyone reading this message ever use this pattern for automatically
counting arguments and passing that argument count to a function?

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

/*** Macros */

#define CountOf(array) (sizeof (array) / sizeof *(array))

/*** Function declarations */

void test(int arg_count, ...);
#define test(...) test(CountOf(((int[]){__VA_ARGS__})), __VA_ARGS__)

/*** Function definitions */

int main(void) {
int i, j, k;

i = j = k = 42;
test(i, ++j, k++);
return 0;
}

#undef test
void test(int arg_count, ...) {
va_list vargs;
int arg;

if (!arg_count) {
printf("No arguments passed!\n");
}

printf("{ ");
va_start(vargs, arg_count);
while (arg_count--) {
arg = va_arg(vargs, int);
printf("%d, ", arg);
continue;
}
va_end(vargs);
printf("}\n");

return;
}
 
S

Shao Miller

Does anyone reading this message ever use this pattern for automatically
counting arguments and passing that argument count to a function?

[...]

Or perhaps a little better would be:

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

/*** Macros */

#define CountOf(array) (sizeof (array) / sizeof *(array))
#define ArgCount(...) (CountOf(((int[]){__VA_ARGS__})))

/*** Function declarations */

void test(int arg_count, ...);
#define test(...) test(ArgCount(__VA_ARGS__), __VA_ARGS__)

/*** Function definitions */

int main(void) {
int i, j, k;

i = j = k = 42;
test(i, ++j, k++);
return 0;
}

#undef test
void test(int arg_count, ...) {
va_list vargs;
int arg;

if (!arg_count) {
printf("No arguments passed!\n");
}

printf("{ ");
va_start(vargs, arg_count);
while (arg_count--) {
arg = va_arg(vargs, int);
printf("%d, ", arg);
continue;
}
va_end(vargs);
printf("}\n");

return;
}
 
J

Jens Gustedt

Am 04/05/2012 09:54 PM, schrieb Shao Miller:
Does anyone reading this message ever use this pattern for automatically
counting arguments and passing that argument count to a function?

[...]

no, because there is a better way to do this.

Your method has downsides:

- it only works for arguments that are assignment compatible to int (or
whichever type you chose for your macro),
- it only determines the value after the preprocessor has run
- it doesn't work with an empty argument list
- your macro evaluates its arguments twice

There are methods to count the number of arguments in the preprocessor
directly, you can look them up with "NARG" on the web. My preprocessor
"library" P99 provides P99_NARG that has none of the downsides above.

Your method has another bizarre aspect, if you think of it. You seem to
be doing all of that to obtain the length of a variable argument list of
identically typed parameters through a compound literal. This makes even
the whole use of va_arg obsolete. Just pass the length and a pointer to
the argument array (the compound literal). This is much less error prone.

On modern platforms combining this with inline can even do a much better
job for optimization than va_argh.

Jens
 
S

Shao Miller

Am 04/05/2012 09:54 PM, schrieb Shao Miller:
Does anyone reading this message ever use this pattern for automatically
counting arguments and passing that argument count to a function?

[...]

no, because there is a better way to do this.

Your method has downsides:

- it only works for arguments that are assignment compatible to int (or
whichever type you chose for your macro),
Sure.

- it only determines the value after the preprocessor has run

It is for functions, not macros. Why is this a down-side?
- it doesn't work with an empty argument list

Isn't that easily fixed with another macro layer?
- your macro evaluates its arguments twice

No, it doesn't, unless VLAs are somehow involved.
There are methods to count the number of arguments in the preprocessor
directly, you can look them up with "NARG" on the web. My preprocessor
"library" P99 provides P99_NARG that has none of the downsides above.

I will check it out. Thank you.
Your method has another bizarre aspect, if you think of it. You seem to
be doing all of that to obtain the length of a variable argument list of
identically typed parameters through a compound literal. This makes even
the whole use of va_arg obsolete. Just pass the length and a pointer to
the argument array (the compound literal). This is much less error prone.

Good point. Thank you.
On modern platforms combining this with inline can even do a much better
job for optimization than va_argh.

That's great.
 
B

Ben Bacarisse

No, I can't say that I have.

Or perhaps a little better would be:

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

/*** Macros */

#define CountOf(array) (sizeof (array) / sizeof *(array))
#define ArgCount(...) (CountOf(((int[]){__VA_ARGS__})))

It forces all the arguments to be convertible to int so it'd not a very
general method. Mind you, that may be a plus point if you want to add
some limited type-checking to an otherwise un-type-checked function
call.

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top