Q: How do you create and use a procedure that has a variable number of arguments?
A: The ANSI edition of The C Programming Language by Kernighan and Ritchie has a fairly good explanation. But there are a couple of things to note.
When you specify the type of the arg in the va_arg macro, you must specify the promoted type. Therefore, since a char is always promoted to int in a variable argument list, it is never correct to use the type char in a va_arg macro. Similarly, you should never use short or float as they are promoted to int or double respectively. You should always used int, double, or a pointer type.
It is not possible for the called function to ask the run-time system how many arguments were passed. So, the function must be able to determine the number and types of all arguments from the fixed arguments. For example, printf can tell how many arguments to print based on the control string that is passed in. You can implement your function using this paradigm, or an EOF marker, or possibly a number denoting the number of arguments to follow.
Following is a simple example that shows how everything interacts:
while ((pType = (char)va_arg(ap, int)) != MY_EOF) {
switch(pType) {
case MY_CHAR:
default:
/* note the promotion to int */
printf("%c", va_arg(ap, int));
break;
case MY_DIGIT:
printf("%d", va_arg(ap, int));
break;
case MY_STR:
printf("%s", va_arg(ap, char *));
break;
}
}
printf("\n");
}
void varArgs(int type, ...)
{
va_list ap;
va_start(ap, type); /* initialize the argument pointer */
if (type == MY_TYPE) {
doVariable(ap);
}
else { /* this case is here to show how you can use vprintf. */
char *fmt = va_arg(ap, char *);
vprintf(fmt, ap);
}
va_end(ap); /* clean up */
}
main()
{
/* you don't need MY_EOF for PRINTF_TYPE msgs because the format string
* lets vprintf know how many args to expect.
*
* A better way to do the MY_TYPE would be to have a format string (like printf) */
varArgs(PRINTF_TYPE, "this is msg #%d for %s\n", 1, "me" );