varargs question
Chris Torek
chris at mimsy.UUCP
Sat Aug 5 08:36:25 AEST 1989
In article <11286 at cit-vax.Caltech.Edu> mazer at bek-owl.caltech.edu
(Jamie Mazer) writes:
>... Our masscomp libs don't have vsprintf() etc, so as a kludge, I
>first tried to cobble something together along the lines of:
> format(a1, a2, a3, ... , a10) /* ugly, but it often works ;-) */
> char *a1, *a2, *a3, ... , *a10)
> { ... sprintf(buf, a1, a2, a3, ... , a10); return(buf) ... }
>
>However, then someone suggested I try the following solution:
> format(va_alist)
> va_dcl
> { ... sprintf(buf, va_alist); return(buf); ... }
>
>The question is, is the second method a valid one?
No.
>Is it legit to pass va_alist into another function like that?
No, not in this form. You may---and should---use something like
this:
char *
format(va_alist)
va_dcl
{
va_list l;
char *fmt;
char buf[SIZE];
va_start(l);
fmt = va_arg(l, char *);
vsprintf(buf, fmt, l);
va_end(l);
return (buf);
}
>If so, then why are the vprintf() functions necessary at all?
The vprintf function is
int vprintf(char *fmt, va_list l);
---that is, it is a function of two arguments, the first being
`char *' and the second `va_list' (usually an array type, making
`l' act like a pointer, or a basic pointer type). The printf function,
on the other hand, is
int printf(char *fmt, ...);
---that is, a function of 1 or more arguments, the first being `char *'
and the rest being undefined. It is legal for compilers to use completely
different calling conventions for the two functions. For instance,
on many machines the `return from subroutine' function can pop a fixed
number of bytes from the call stack. On such a machine, one might
compile
vprintf("foo %d bar %o\n", l);
fn();
as
.string Lxxx,"foo %d bar %o\n"
push #Lxxx # push address of string
push 8(frame) # push value of l
call vprintf_ # vprintf()
call fn_ # fn()
.
.
.
vprintf_:
<code> # arg 1 is -8(frame), arg 2 is -4(frame)
ret 2 # pop two arguments
but
printf("foo %d bar %o\n", x, y);
fn();
as
.string Lxxx,"foo %d bar %o\n"
push 16(frame) # push value of y
push 12(frame) # push value of x
push #Lxxx # push address of string
call printf_ # printf()
pop r0 # clear stack
pop r0
call fn_ # fn()
.
.
.
printf:
<code> # arg 1 is -4(frame), arg2 -8(frame), etc
ret 1 # pop 1 fixed argument
Note that I switched the *order* of the arguments; this too is legal,
although I have never seen a compiler go this far. (One would be
more likely to see a compiler pass arguments to fixed-argument functions
in registers, and variable-argument functions on a stack, for instance.)
In principle, then (if not in acutal implementation on certain machines),
printf and vprintf are entirely different beasts.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: chris at mimsy.umd.edu Path: uunet!mimsy!chris
More information about the Comp.unix.wizards
mailing list