Do you use stdarg, varargs or ya-args?

Chris Torek torek at elf.ee.lbl.gov
Fri May 10 22:00:18 AEST 1991


In article <2755 at muffin.cme.nist.gov> libes at 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 at ee.lbl.gov



More information about the Comp.lang.c mailing list