VA_ARG
Re:VA_ARG
Get a better book, or the HTML library reference from http://www.dinkumware.com, which is also available online and says this on stdarg.h.Dragon_Hilord wrote: My book doesn't say how to use the VA_ARG macros so could anybody enlighten me?
Every good solution is obvious once you've found it.
Re:VA_ARG
Well, the Dinkumware site comes with a usage example... if that isn't what you were looking for, tell me what you meant, i.e. what is unclear to you, and I'll try to nail it down.
Every good solution is obvious once you've found it.
Re:VA_ARG
OK, I'll simplify it a bit:
You have a function with at least one fixed argument and an elipsis. To read the variable argument list, you need an va_list object, which is declared by
va_list ap;
Then you have to initialize ap, i.e. tell it where on the stack to look for the first argument. For this, you use the last of the fixed arguments, and pass that as parameter to va_start:
va_start( ap, s );
Now, you can make sequential calls to va_arg, using the va_list object and the expected type as parameter:
t = va_arg( ap, char * )
Beware - there is no such thing as an "end of list". Your (...) function and its caller have to agree on some way to terminate the argument list (e.g. NULL pointer), as an va_arg beyond the last argument will bring death to your program.
When you're done, you call va_end for cleanup:
va_end( ap );
The last macro, va_copy, is only available for C99, and a dangerous beast if you don't know your va_args by heart, so better stay away from it first.
Code: Select all
#include <stdarg.h>
void foo(char *s, ...)
{
va_list ap;
va_start(ap, s);
while (t = va_arg(ap, char *))
{
bar( t );
}
va_end(ap);
}
va_list ap;
Then you have to initialize ap, i.e. tell it where on the stack to look for the first argument. For this, you use the last of the fixed arguments, and pass that as parameter to va_start:
va_start( ap, s );
Now, you can make sequential calls to va_arg, using the va_list object and the expected type as parameter:
t = va_arg( ap, char * )
Beware - there is no such thing as an "end of list". Your (...) function and its caller have to agree on some way to terminate the argument list (e.g. NULL pointer), as an va_arg beyond the last argument will bring death to your program.
When you're done, you call va_end for cleanup:
va_end( ap );
The last macro, va_copy, is only available for C99, and a dangerous beast if you don't know your va_args by heart, so better stay away from it first.
Every good solution is obvious once you've found it.
Re:VA_ARG
always struck me as odd the way the va_args worked. you would have thought it would have pushed say 3, then 3 arguments so the functions knew how many args to safely use etc...
-- Stu --
Re:VA_ARG
The reason va_args works is an unfortunate result of some historical facts:
The calling convention is designed for fixed arguments. In fixed argument case any argument count would be just bloat. So we only push arguments.
Ok, so why not push the number in variable case? Because in traditional C you don't need to tell anyone anything about your arguments. If you don't have a prototype, then we must expect that your function takes any number of arguments and return int.
So we would really have to pay the price of variable arguments for EVERY function, because any function can be compiled agaist without knowing it's type. Not that this would really matter with modern machines, but since the va_args hack is already accepted the way it works, why change it anymore?
Anyway, essentially you need to push that number anyway, because you need to pass a single argument anyway, and you really use that single argument to see how many futher arguments there are. That could be made implicit, but in case of something like printf, it would be just extra bloat anyway.
Besides, if I was designing a new calling convention (or should I say when, since I'm also interested in language issues) it'd pass the number of arguments in a register instead. And I'd also put arguments ABOVE the return address and declare them callee-pop because that'd make tail-call elimination possible.
The calling convention is designed for fixed arguments. In fixed argument case any argument count would be just bloat. So we only push arguments.
Ok, so why not push the number in variable case? Because in traditional C you don't need to tell anyone anything about your arguments. If you don't have a prototype, then we must expect that your function takes any number of arguments and return int.
So we would really have to pay the price of variable arguments for EVERY function, because any function can be compiled agaist without knowing it's type. Not that this would really matter with modern machines, but since the va_args hack is already accepted the way it works, why change it anymore?
Anyway, essentially you need to push that number anyway, because you need to pass a single argument anyway, and you really use that single argument to see how many futher arguments there are. That could be made implicit, but in case of something like printf, it would be just extra bloat anyway.
Besides, if I was designing a new calling convention (or should I say when, since I'm also interested in language issues) it'd pass the number of arguments in a register instead. And I'd also put arguments ABOVE the return address and declare them callee-pop because that'd make tail-call elimination possible.
Re:VA_ARG
You have to keep in mind that C was around long before any efforts at standardization were made. It was a mess well before ANSI C came out, and they had to respect what already was common practice, or no-one would have adopted ANSI/ISO C in the first line.
As opposed to Java, which was cast in the laboratory and was "ready" when released - and made into a mess only afterwards. ;D
As opposed to Java, which was cast in the laboratory and was "ready" when released - and made into a mess only afterwards. ;D
Every good solution is obvious once you've found it.
Re:VA_ARG
You should read the paragraph P.J. Plauger wrote in his book, "The C Standard Library", about the angst that struck the ANSI C committee when they learned that the ISO C committee was quite determined to have ISO C differ from ANSI C... and how they scrambled to fix the one main deficit ISO perceived in ANSI C: locales. Took them another year or so.
I can picture it. ANSI C and ISO C differing, now that would have been a fine mess for library and compiler implementors...
I can picture it. ANSI C and ISO C differing, now that would have been a fine mess for library and compiler implementors...
Every good solution is obvious once you've found it.
Re:VA_ARG
@Solar: ummm. I'm having a problem :-X... I keep getting the error that va_list doesn't exist. Also I get problems with something to do with a comma operator. When I run the preprocessor on it to see what it's doing, it appears that everything is honkey-dorie except va_list which remains the same (vim colors it like an internal command). Any input? Thanks in advance!
Cheers, DH
Cheers, DH