[comp.sources.d] varargs

chris@mimsy.UUCP (04/06/87)

In article <2285@ncoast.UUCP> allbery@ncoast.UUCP (Brandon Allbery) writes:
>Note that varargs is defined such that it will work even on machines such as
>the Pyramid which pass arguments in registers (common on RISC machines).

Or on the MIPS machines.

>You MUST declare only one argument -- va_alist -- and include the type of it
>as "va_dcl" without a semicolon.

`va_alist' and `va_dcl' are often (always?) macros.  It is conceivable
that on a machine that passes the first two arguments in registers and
the third through nth on the stack, these might be

	#define va_alist  _p1, _p2, _p3
	#define va_dcl int _p1, _p2, _p3;

in which case va_start might be

	#define va_start(l) { \
		struct _va_info _va; \
		_va.reg = 2; _va.r[1] = _p1; _va._r[0] = _p2; \
		_va.addr = &_p3; \
		(l) = &_va;

and va_arg then

	#define va_arg(l, t) \
		(sizeof(t) == 8 ? \	/* size always 8 or 4 in this arch. */
		 (ugly code to handle double float with spanning &c) : \
		 (--(l)->reg >= 0 ? *(t *)&(l)->r[(l)->reg] : \
		  ((l)->addr++, ((t *)((l)->addr))[-1])))

(and va_end would simply be defined as `}').

This would indeed preclude usage like

	f(fmt, va_alist)
		char *fmt;
		va_dcl
	{
		...

The reason I mention this is that in fact, on the Pyramid, Sun,
and Vax (all implementations of which I am aware), usages such as
that above in fact work.  I wonder, then, if this has been guaranteed
anywhere.  Has it?  (I know, I should dig out a copy of the X3J11
draft....)

>(C compilers can then recognize this directly to do any special
>processing needed, as for the Pyramid.)

Actually, Pyramid manages it without compiler hooks.  I believe
MIPS uses compiler hooks, though.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!mimsy!chris	ARPA/CSNet:	chris@mimsy.umd.edu

scs@adam.pika.mit.edu (Steve Summit) (08/18/89)

In article <9847@j.cc.purdue.edu> nwd@j.cc.purdue.edu (Daniel Lawrence) writes:
>I support uEMACS on a
>number of systems and compilers that do not have varargs.h, and I do not
>want to simply tell a lot of users there machines must be updated or
>changed because of this.

If you can implement varargs functions without <varargs.h>,
hoping that it will work on unknown systems, then you can write
your own <varargs.h> (or, better yet, <stdarg.h>) and supply it
with your distribution, for use by recipients whose (beleagured)
systems do not have the proper header file.  Of course, this
solution won't work for all recipients, but it's no worse than
"simulating" varargs in-line.  In fact, it's better: it works for
the same cases, it fails for systems that don't have the header
file and for which the hardwired code code wouldn't have worked
either, and (key point:) it allows the program to work on "weird"
systems for which the handcoded stuff wouldn't work but on which
a working varargs and/or stdarg implementation is provided.

Here's my own <stdarg.h>, which you're all welcome to. (Just
leave my name on it.)  For those who don't know, stdarg is the
X3J11 (ANSI) C standard package which supplants, and is said
to be more widely implementable than, varargs.  Since it is now
(or almost) standard, it is a good choice for portable code,
particularly if a quasi-portable implementation can be supplied
for systems which don't yet have it.

I find the stdarg package slightly easier to use than varargs.
There is no va_dcl macro or va_alist placeholder argument.  The
varargs function is compiled with at least one fixed argument
(some find this requirement discouraging); the name of the last
fixed argument is passed to the va_start macro, along with the
argument pointer variable, which is of type va_list.  The va_arg
and va_end macros are used just as under <varargs.h>.

                                            Steve Summit
                                            scs@adam.pika.mit.edu

--------8<--------8<--------stdarg.h--------8<--------8<--------
#ifndef _STDARG_H
#define _STDARG_H

/*
 *  stdarg implementation for "conventional" architectures with
 *  downward-growing stacks.  The stack is assumed to be aligned
 *  to word, i.e. int, sized boundaries, with smaller arguments
 *  widened when passed and larger arguments equal to (or rounded
 *  up to) a multiple of the word size.
 *
 *  The stack word size can be changed by adjusting the
 *  _stacktype typedef.
 *
 *  The va_arg macro looks inefficient, with its embedded
 *  conditional, and lint may complain about "constant in
 *  conditional context," but the optimizers I have tried it
 *  under successfully remove the "dead" case (the controlling
 *  expression is a compile-time constant), and the remaining
 *  postincrement int pointer expression (the more common case)
 *  is considerably nicer in space and time.
 *
 *  Bug: doesn't know that float arguments are widened to double
 *  when passed.  Don't, therefore, call va_arg(..., float).
 *
 *  Steve Summit  4/15/89
 */

typedef int _stacktype;
typedef _stacktype *va_list;

#define _argsize(type) ((sizeof(type) + (sizeof(_stacktype) - 1)) \
				/ sizeof(_stacktype))

#define va_start(vaptr, lastarg) vaptr = (_stacktype *)&lastarg + 1

#define va_arg(vaptr, type) (_argsize(type) == 1 ? \
	*(type *)((vaptr)++) : \
		*(type *)(((vaptr) += _argsize(type)) - _argsize(type)))

#define va_end(vaptr)

#endif