Reputation: 150
I'm studying the C programming language and one thing I found very interesting is the implementation of a variadic function. I'm currently trying to print each value passed into the function, but I'm only getting a part of the arguments.
I tried running some examples I found online for average number from parameters and also a sum algorithm (shown below).
#include <stdio.h>
#include <stdarg.h>
int sum(int count, ...)
{
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
int num = va_arg(args, int);
total += num;
printf("Value #%d: %d\n", i, num);
}
va_end(args);
return total;
}
int main()
{
int result = sum(1, 2, 3, 4, 5);
printf("The result is: %d\n", result);
}
The code above only prints:
Value #0: 2
The result is: 2
I think it's because the for
loop is using the first argument as the max value of the index. But...
My question here is how printf
works if it's not necessary to pass the amount of arguments to replace within the formatted string?
Is it because behind the scenes, the C runtime counts how many format specifiers are declared in the formatted string? That's my guess.
Upvotes: 0
Views: 1366
Reputation: 4247
If you call your variadic function as:
int result = sum(5 /*count*/, 1, 2, 3, 4, 5);
by adding the initial 5
(a count), it will do what you expect it to, but for fun try calling it with a bigger number (say, 6 or 10) and see what happens. They are easy to get wrong.
Almost the only good case for variadic functions is for variants of printf tailored for your application. My longtime favorite is die()
that takes a printf-style format string (and arguments), sends it to the standard error, appends a newline, then exits the program.
#include <stdlib.h>
#include <stdarg.h>
void die(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
exit(EXIT_FAILURE);
}
and then put this in your header files to use it:
extern void die(const char *format, ...)
__attribute__((noexit)) // function never exits
__attribute__((printf(1, 2))); // looks like printf, format is arg1
Now you can call die("Program failed because %s", reason);
and it bails on the program without a lot of muss and fuss. And because of the __attribute__
use, the compiler (GNU, at least) knows how to verify the parameters to the format string.
Upvotes: 0
Reputation: 780673
There's no way to find out how many arguments were actually supplied.
printf()
figures it out from the format string. Each of the %
operators in the format string corresponds to an argument (this is a simplification), it processes as many arguments as it needs to fill each of them in.
So if you write:
printf("%d %s\n", intvar, stringvar);
it knows that there must be 2 additional arguments: one for %d
and another for %s
.
Another method used by some functions is a sentinel value to indicate the last argument.
execl("program", "arg0", "arg1", "arg2", (char *)NULL);
execl()
processes arguments until it gets to the NULL
value.
Upvotes: 4