Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!iuvax!purdue!haven!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.unix.wizards Subject: Re: varargs question Keywords: varargs vsprintf Message-ID: <18905@mimsy.UUCP> Date: 4 Aug 89 22:36:25 GMT References: <11286@cit-vax.Caltech.Edu> Distribution: usa Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 106 In article <11286@cit-vax.Caltech.Edu> mazer@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_: # 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: # 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@mimsy.umd.edu Path: uunet!mimsy!chris