[comp.lang.c] problems with varargs

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