[comp.lang.c] Do you use stdarg, varargs or ya-args?

libes@cme.nist.gov (Don Libes) (05/10/91)

All the STDC (-like) compilers I use support varargs.  (To be
explicit, this includes Borland, DEC, GNU, and Microsoft compilers.)
All the non-STDC compilers I use (too many to name) support varargs.

Naturally, the non-STDC compilers don't support stdarg.

The obvious question is: why bother using stdarg?  Is any vendor
really going to omit varargs 5 or even 10 years from now?  I seriously
doubt it.  (I'm betting one of my coworkers money on this.)  I suppose
that eventually one may have to explicitly use some flag when
compiling (say "-varargs"), but don't you think the support will
always be provided by the vendor somehow?  (All the STDC compilers
already provide a shitload of extensions.)

Yes, programs that use varargs are not conforming, but we (and I'm
speaking strictly for my coworkers here) are trying for maximal
portability in unknown environments.  Either there is a curious irony
here or I don't understand why STDC invented stdarg.  (Admittedly,
some non-STDC compilers don't even support varargs.)

Some of my coworkers use 1) only stdargs, 2) only varargs, or 3) both
with ifdefs to select between them.  Other possibilities are 4) a macro
package to cover-up the choice, 5) avoid entirely, and 6) you don't
know what I'm talking about and pass everything as if it were an int.

(1) This makes sense to me if you are writing for and only for a STDC
environment.  Otherwise it just doesn't fly in the real world.
(3) Ghastly to read and write.
(4) Code doesn't look like STDC, and it raises the question of the
original point of the invention of stdarg if it's never actually used
directly.  Unfortunately, there ain't no way to make the STDC macros
work on top a varargs implementation.  Even worse, how do you explain
to a new C programmer that they shouldn't use what's in STDC?

Obviously, I think people who subscribe to (3) or (4) are misguided.

Don Libes          libes@cme.nist.gov      ...!uunet!cme-durer!libes

torek@elf.ee.lbl.gov (Chris Torek) (05/10/91)

In article <2755@muffin.cme.nist.gov> libes@cme.nist.gov (Don Libes) writes:
>The obvious question is: why bother using stdarg?

There is one minor efficiency reason, and, of course, the `standardness'
argument.

The efficiency reason comes about because varargs() officially works
like this:

	#include <varargs.h>

	/* foo takes three fixed arguments and the rest are variable */
	/* VARARGS3 */
	void
	foo(va_alist)		/* example 1 */
		va_dcl
	{
		va_list ap;
		XYZ *xp;
		int i;
		long l;

		va_start(ap);
		xp = va_arg(ap, XYZ *);
		i = va_arg(ap, int);
		l = va_arg(ap, long);
		/* code to deal with varargs goes here */
		va_end(ap);
	}

People (including myself) often write something like:

	/* VARARGS3 */
	void
	foo(xp, i, l, va_alist)	/* example 2 */
		XYZ *xp;
		int i;
		long l;
		va_dcl
	{
		va_list ap;

		va_start(ap);
		/* code to deal with varargs goes here */
		va_end(ap);
	}

but this is not in fact correct.  (I know of no systems on which it
breaks, but that does not mean such do not exist.)

Where I believe ANSI went wrong is in adding a second parameter to
va_start.  The `...' syntax is not as great a problem.  If one takes
the attitude (as I have done) that `if example 1 fails, get an ANSI
C compiler or forget it', we can then write foo() as:

	#if __STDC__
	void foo(XYZ *xp, int i, long l, ...) {
	#else
	void foo(xp, i, l, va_alist) XYZ *xp; int i; long l; va_dcl {
	#endif
		va_list ap;

		va_start(ap);
		/* code to deal with varargs goes here */
		va_end(ap);
	}

which cuts the work in half when compared with the (currently required
under the exact same assumptions):

	/* example 3 */
	#if __STDC__
	void foo(XYZ *xp, int i, long l, ...) {
	#else
	/* VARARGS */
	void foo(xp, i, l, va_alist) XYZ *xp; int i; long l; va_dcl {
	#endif
		va_list ap;

	#if __STDC__
		va_start(ap, l);
	#else
		va_start(ap);
	#endif
		/* code to deal with varargs goes here */
		va_end(ap);
	}

In any case, the requirement that the name of the last fixed argument
be repeated is a maintenance headache.  The compiler already must
understand the new `...' syntax; it is little, if any, more difficult
to add at the same time one more special compiler-specific syntax or
semantic (which is then hidden behind va_start in <stdarg.h>) for
computing the address of the first varying argument.  Thus even though
the `extra' argument to va_start can be hidden behind Yet Another
Macro:

	#if __STDC__
	#define VASTART(ap, last) va_start(ap, last)
	#else
	#define VASTART(ap, last) va_start(ap)
	#endif

so that example 3 becomes:

	/* example 4 */
	#if __STDC__
	void foo(XYZ *xp, int i, long l, ...) {
	#else
	/* VARARGS */
	void foo(xp, i, l, va_alist) XYZ *xp; int i; long l; va_dcl {
	#endif
		va_list ap;

		VASTART(ap, l);
		/* code to deal with varargs goes here */
		va_end(ap);
	}

, I still believe that this extra argument was a mistake.

>... don't you think [old varargs style] support will always be provided
>by the vendor somehow?  (All the STDC compilers already provide a
>shitload of extensions.)

Always: no; for the next 20 years: yes. :-)  (Incidentally, I have
forgotten: is a shitload more or less than an oodle?  I think the list
goes: one, a couple, a few, some, a dozen, a baker's dozen, lots,
oodles, a shitload, a metric shitload, ... [where is George Weinert
when you need him? :-) ])
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (05/10/91)

In <2755@muffin.cme.nist.gov> libes@cme.nist.gov (Don Libes) writes:

>All the STDC (-like) compilers I use support varargs.  (To be
>explicit, this includes Borland, DEC, GNU, and Microsoft compilers.)
>All the non-STDC compilers I use (too many to name) support varargs.

Some months ago I had the dubious honor of porting 110,000 lines of
UNIX C code to run under the pretty-much-ANSI-conformant High-C
compiler from Metaware.  In this environment, varargs.h is a hard link
to stdarg.h.

So varargs.h is supported, but that doesn't mean that "varargs" is
supported -- your variadic functions had better use the "..." syntax
and the ANSI macros, though you can #include either varargs.h or
stdarg.h, whichever you prefer...
--
Rahul Dhesi <dhesi@cirrus.COM>
UUCP:  oliveb!cirrusl!dhesi

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (05/10/91)

In <13041@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) defines
this convenience macro:

     #if __STDC__
     #define VASTART(ap, last) va_start(ap, last)
     #else
     #define VASTART(ap, last) va_start(ap)
     #endif

I would like to know if there is anything in the ANSI C standard that
guarantees that this will work.  Using the Metaware High C compiler
(which I mention in another posting), I found that it didn't.  The High
C compiler was doing some fancy token-pasting in its va_start macro,
and that token pasting didn't work right if I defined my own macro that
invoked va_start.  It caused me three days of pain.
--
Rahul Dhesi <dhesi@cirrus.COM>
UUCP:  oliveb!cirrusl!dhesi

meissner@osf.org (Michael Meissner) (05/10/91)

In article <2755@muffin.cme.nist.gov> libes@cme.nist.gov (Don Libes)
writes:

| The obvious question is: why bother using stdarg?  Is any vendor
| really going to omit varargs 5 or even 10 years from now?  I seriously
| doubt it.  (I'm betting one of my coworkers money on this.)  I suppose
| that eventually one may have to explicitly use some flag when
| compiling (say "-varargs"), but don't you think the support will
| always be provided by the vendor somehow?  (All the STDC compilers
| already provide a shitload of extensions.)

A couple of things:

   1)	There were two or three machines that could not support
	varargs in any fashion (I don't remember the particulars).

   2)	Then there was pyramid which had '{' in va_start, and '}' in
	va_end.

   3)	The MIPS based computers also have a subtle bug with varargs.
	In the MIPS calling sequence, if the first two arguments were
	floating point, they were passed in FP registers, rather than
	the GP registers.  However, varargs only works on the GP
	register set, so that if you have a varargs function which
	takes a floating point value as the first argument, the
	wrong values are used.

   4)	On the 32x32 systems, arguments are typically passed on the
	stack.  However, for building the kernel, the convention is
	that the first two arguments are passed in r0 and r1.  This
	breaks varargs programs, so I recently modified GCC to always
	pass arguments to stdargs functions on the stack.
--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142

Considering the flames and intolerance, shouldn't USENET be spelled ABUSENET?

gwyn@smoke.brl.mil (Doug Gwyn) (05/11/91)

In article <2755@muffin.cme.nist.gov> libes@cme.nist.gov (Don Libes) writes:
>All the STDC (-like) compilers I use support varargs.

Not all the standard-conforming compilers that *I* use!

>Yes, programs that use varargs are not conforming, but we (and I'm
>speaking strictly for my coworkers here) are trying for maximal
>portability in unknown environments.  Either there is a curious irony
>here or I don't understand why STDC invented stdarg.

X3J11 invented ,...) and <stdarg.h> because there was a need for them
in some implementation environments, and the <varargs.h> va_start macro
did not have a slot for the crucial "hook" on a known parameter that is
needed by some reasonable implementations.

For portability, you need to code for three environments:
	(a) <stdarg.h> exists; you can rely on this #if __STDC__.
	(b) <varargs.h> exists; you can almost rely on this #if unix.
	(c) neither header exists; you might be able to provide your
	    own implementation of <varargs.h> for such an environment,
	    or you could try pretending that there are more arguments
	    than needed, which is a kludge that works in many cases.