mazer@bek-owl.caltech.edu (Jamie Mazer) (07/16/89)
Recently, I have found I needed something like the C++ form function (I believe this came up pretty recently in another list as well). 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? It seems to work on our SUNs, but not reliably on the Masscomp, though for the life of me, I can't figure out where and when it blows up. Is it legit to pass va_alist into another function like that? If so, then why are the vprintf() functions necessary at all? Thanks, /Jamie UUCP: {rutgers,ames}!cit-vax!bek-owl!mazer ARPA: mazer@bek-owl.caltech.edu "It's a fine line between line between BITNET: jmazer@caltech.bitnet clever and stupid" -- Spinal Tap
chris@mimsy.UUCP (Chris Torek) (08/05/89)
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_: <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@mimsy.umd.edu Path: uunet!mimsy!chris