cmi@eleazar.Dartmouth.EDU (Theo Pozzy/R. Green) (01/21/88)
I'm have a problem working with the standard *nix varargs construct. What I'm basically trying to do is implement two levels of variable argument passing, similar to what the vprintf() routine must be doing. Now, I don't have the sources to vprintf, and I don't know if it can be done portably in the context of the varargs guidelines. The basic idea is to have a routine like printf(), which calls another routine, like fprintf(), passing one argument in addition to the arguments passed to it. The first routine to get called, which works fine, looks like this: myprintf(fmt, va_alist) char *fmt; va_dcl { va_list vap; va_start(vap); /* here I can pull of the arguments with no problem */ myfprintf(stdout,fmt,vap); va_end(vap); } Here's what I've tried, which doesn't work, for myfprintf(): myfprintf(f, fmt, va_alist) FILE *f; char *fmt; va_dcl { va_list vap; va_start(vap); /* at this point, the va_arg() routine doesn't return the arguments correctly */ va_end(vap) } Is there anyone out there who has a good handle on varargs that can tell me the right (portable) way to do this? Is there someone with the source to vprintf() with some insight? Thanks, Theo Pozzy, Corporate Microsystems, Inc. ...!decvax!dartvax!eleazar!cmi (UUCP) cmi@eleazar.dartmouth (CSNET) cmi%eleazar@dartmouth.edu (ARPA) Box A-58, Hanover, NH, 03755 (USPS) CompuServe (76267,413) (603) 448-5193 (BellNet) -- Theo Pozzy, Corporate Microsystems, Inc. ...!decvax!dartvax!eleazar!cmi (UUCP) cmi@eleazar.dartmouth (CSNET) cmi%eleazar@dartmouth.edu (ARPA) Box A-58, Hanover, NH, 03755 (USPS) CompuServe (76267,413) (603) 448-5193 (BellNet)
blarson@skat.usc.edu (Bob Larson) (01/22/88)
In article <7962@eleazar.Dartmouth.EDU> cmi@eleazar.Dartmouth.EDU (Theo Pozzy/R. Green) writes: >I'm have a problem working with the standard *nix varargs construct. >myprintf(fmt, va_alist) >char *fmt; >va_dcl >{ >va_list vap; >va_start(vap); >/* here I can pull of the arguments with no problem */ >myfprintf(stdout,fmt,vap); >va_end(vap); >} va_alist MUST be the only argument to a varargs function. (Lint (sun 3.2) gets this horrably WRONG. If you don't get a ton of error messages from lint you made a mistake. (This is another case where something non-portable happens to work on 4.2bsd so people assume it works everywhere.) myprintf(va_alist) va_dcl { va_list vap; char *fmt; va_start(vap); fmt = va_arg(vap, char *); myfprintf(stdout, fmt, vap); va_end(vap); } >myfprintf(f, fmt, va_alist) >FILE *f; >char *fmt; >va_dcl >{ >va_list vap; >va_start(vap); >/* at this point, the va_arg() routine doesn't return the arguments correctly */ >va_end(vap) >} This is where your major mistakes are. myfprintf(f, fmt, vap) FILE *f; char *fmt; va_list vap; { /* va_arg should work here */ } Note that you may have to pass a pointer to vap on systems that va_list is a structure but don't have structure passing. -- Bob Larson Arpa: Blarson@Ecla.Usc.Edu blarson@skat.usc.edu Uucp: {sdcrdcf,cit-vax}!oberon!skat!blarson Prime mailing list: info-prime-request%fns1@ecla.usc.edu oberon!fns1!info-prime-request
chris@mimsy.UUCP (Chris Torek) (01/22/88)
In article <7962@eleazar.Dartmouth.EDU> cmi@eleazar.Dartmouth.EDU (Theo Pozzy/R. Green) writes: >The basic idea is to have a routine like printf(), which calls another >routine, like fprintf(), passing one argument in addition to the arguments >passed to it. The basic trick (if I may phrase it so) is to have only one va_alist parameter anywhere in the chain. printf() does not call fprintf(); printf() calls vfprintf(): myprintf(fmt, va_alist) char *fmt; va_dcl { va_list vap; va_start(vap); myvfprintf(stdout, fmt, vap); va_end(vap); } myfprintf(f, fmt, va_alist) FILE *f; char *fmt; va_dcl { va_list vap; va_start(vap); myvfprintf(f, fmt, vap); va_end(vap) } myvfprintf(f, fmt, ap) FILE *f; char *fmt; va_list ap; { ... } -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/23/88)
#include <stdio.h> /* for `stdout' */ #include <varargs.h> void myprintf( va_alist ) /* NOTE: do not declare any "fixed" args here */ va_dcl { void myfprintf(); char *fmt; va_list ap; va_start( ap ); fmt = va_arg( ap, char * ); /* pick up "fixed" arg like this */ /* access the first few arguments via va_arg, as needed */ myfprintf( stdout, fmt, ap ); va_end( ap ); } void myfprintf( f, fmt, ap ) FILE *f; char *fmt; va_list ap; /* NOTE: type must agree with caller! */ { /* access the remaining arguments via va_arg, as needed */ }
guy@gorodish.Sun.COM (Guy Harris) (01/23/88)
> va_alist MUST be the only argument to a varargs function. (Lint (sun > 3.2) gets this horrably WRONG. If you don't get a ton of error > messages from lint you made a mistake. Gee, I guess AT&T made a mistake, too, because that code linted quite happily on a 3B2 running S5R3.1. 4.2BSD has nothing to do with it.... Fortunately, ANSI C repairs this deficiency; va_alist need not be the only argument to a "stdargs" function. "va_start" takes an extra argument, which is the last non-varargs parameter to the function; presumably, this is intended to permit this to work on machines where "varargs" won't work if "va_alist" isn't the only argument to the function (I presume they exist, although none of the machines I've worked with, including my trusty Sun-4, have a problem with this). Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com