How exactly does va_list work(and its macros) and how would i put it into my OS
and ummm well I guess thats it
putting va_list into my OS
Re:putting va_list into my OS
It's compiler-dependent, take a look at your platform's <stdarg.h>. Or maybe take a look at the (slightly more) generic version from PDCLib.
Re:putting va_list into my OS
"How it works" is ambiguous - do you mean usage, function, or implementation?
Usage, demonstrated by some pseudo-printf:
I.e., you declare an object of type va_list, initialize it with va_start(), and then use va_arg() to read specific types from the list. Don't forget to use va_end() when you are done with your va_list object - on some architectures, va_list implies some dynamic memory management, and while you're getting away without va_end() on e.g. x86, it's not strictly correct to omit it.
As for how it works... on x86, basically what you're doing is peeking the stack. va_start() takes the address of the last "named" variable, and va_arg() uses sizeof( type ) to walk down the stack to get the next value. Needless to say, if you try to read more arguments than there are on the stack, your hard drive gets formatted ("undefined behaviour").
Other platforms might do it in a completely different way.
As for implementation... it's not much code, actually, and paulbarker correctly pointed out where to find it. GCC provides its own generic version somewhere in /usr/lib/gcc..., or you might follow the link in my signature to find internals/_PDCLIB_config.h of PDCLib v0.4 containing a PD generic implementation that works fine at least on x86, too.
(Note for people reading this post a couple of weeks later: Exact location of the code in PDCLib sources might change.)
Usage, demonstrated by some pseudo-printf:
Code: Select all
int printf( const char * format, ... )
{
va_list ap;
va_start( ap, format ) /* i.e., second parameter = last named variable before elipsis (...) */
...
switch ( format[i] ) /* being the conversion specifier */
{
case 'd': {
int value = va_arg( ap, int );
/* print value */
}
case 'f': {
double value = va_arg( ap, double );
/* print value */
}
case 's': {
char * value = va_arg( ap, char * );
/* print value */
}
...
}
...
va_end( ap );
}
As for how it works... on x86, basically what you're doing is peeking the stack. va_start() takes the address of the last "named" variable, and va_arg() uses sizeof( type ) to walk down the stack to get the next value. Needless to say, if you try to read more arguments than there are on the stack, your hard drive gets formatted ("undefined behaviour").
Other platforms might do it in a completely different way.
As for implementation... it's not much code, actually, and paulbarker correctly pointed out where to find it. GCC provides its own generic version somewhere in /usr/lib/gcc..., or you might follow the link in my signature to find internals/_PDCLIB_config.h of PDCLib v0.4 containing a PD generic implementation that works fine at least on x86, too.
(Note for people reading this post a couple of weeks later: Exact location of the code in PDCLib sources might change.)
Every good solution is obvious once you've found it.