[net.lang.c] varargs

crm@duke.UUCP (10/14/83)

Can any of you C wizards out there tell me how it is one implements
variable arguments in C?

Also,  many thanks to all the people who responded to my request for
a better cb -- I even got one in the mail today!  It's all in, and it
works, and I would send out individual thanks to all the people who
responded except there were lots(!) of them.

Anyway, thanks again ... how you say ... :-)

Charlie Martin
...!duke!crm

henry@utzoo.UUCP (Henry Spencer) (10/16/83)

How do you implement variable numbers of arguments in C?  In a word,
unportably.  (Is that a word?)  The implementation is fundamentally
machine-dependent.  There are portable "library" facilities for doing
it in some Unixes, but the insides of those libraries are still quite
machine-dependent.  Scanning a variable-length argument list requires
knowing the C calling sequence on the machine in question, so that you
know how the arguments are laid out in core.  Machines differ enough
on this point that machine-independent code for it is impossible.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

dave@utcsrgv.UUCP (Dave Sherman) (10/16/83)

Charlie Martin (duke!crm) asks how to implement variable arguments.
In C or on a particular machine? As Henry Spencer points out, it's not
portable and therefore not strictly valid C. However, on a PDP-11
or VAX, you can have the routine

routine(firstarg)
	int *firstarg;
{
	int **argptr;
	argptr = &firstarg;
	...
	argptr++;
	...
}

and refer to *argptr to mean your arguments, **argptr if you want
the character it points to, etc. I have several programs which do
this sort of thing. It's obviously not guaranteed to be portable
to other machines.

It is a useful construct, though, and it seems quite likely that
for any given machine you want to take such code to, you can figure
out what needs doing. Those arguments have to get passed somehow,
so although the incrementing might be different the same basic
technique should continue to work.


Dave Sherman
Toronto
-- 
 {cornell,decvax,ihnp4,linus,utzoo,uw-beaver}!utcsrgv!lsuc!dave

kendall@wjh12.UUCP (Sam Kendall) (10/17/83)

Henry@Utzoo notes, and seems to object to, the fact that variable 
argument functions are implemented nonportably, even though the package 
has a portable interface.  It seems to me that one of the good points of 
portable libraries such as the Standard I/O Library and the portable C 
library in general (not that there is just one) is the possibility of 
having a portable interface but a nonportable implementation.  There are 
other functions be that cannot have a single, portable implementation: 
setjmp() and longjmp(), for instance; and it may be advantageous to code 
functions in assembler or nonportable C, for efficiency, that could be 
coded portably in C.  

Here is a real difference between Ada and C (how perceptive of me!): Ada
is designed to make it much easier to give even seemingly
machine-dependent functions portable implementations, and to make it
easy to seperate the machine-dependent from the machine-independent
otherwise.  This is done by (1) moving machine dependencies into the
compiler, and (2) providing good language facilities for seperation,
such as (in C terms) the ability to seperate the structure members from
their layout, and to seperate enum members from their numeric values.
Not to mention a good way to seperate the government from its money.

	Sam Kendall		  {allegra,ihnp4}!wjh12!kendall
	Delft Consulting Corp.	    decvax!genrad!wjh12!kendall

henry@utzoo.UUCP (Henry Spencer) (10/22/83)

I'm not so much *objecting* to the machine-dependent nature of
variable-length-arg-list routines, as trying to point out that
their implementation *is* fundamentally machine-dependent and
there is *no* *way* *around* *this*.  This is in response to
numerous people proposing one notion after another of how to do
something that simply cannot be done.  Worse, some of their schemes
do work on *some* machines, and people who don't understand the
messiness of the issue might assume that they work everywhere.
I've had enough encounters with unportable software as a result of
such assumptions to think it worthwhile to try to head this particular
problem off.

Yes, I'm aware of the library packages under 4BSD and System V that
try to at least bury the machine-dependencies in a library.  Be warned
that even they don't suffice on sufficiently bizarre machines.

The most common reason for wanting vararg routines other than the
standard ones is a desire to write an error-handling routine that
puts out a printf-style message and then does some program-dependent
cleanup actions.  The *only* 100% portable way to do this is:

	sprintf(buf, ".....", ....);
	error(buf);

I know it's a nuisance to do two calls instead of one, and the need
to have a buffer variable is annoying, but this code is guaranteed
to be fairly portable, while using %r, _doprnt, &args, etc. is not.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

ken@turtleva.UUCP (Ken Turkowski) (10/24/83)

Another way to get portable error message routines is to assume that
there will be a maximum number of arguments.

error(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
char *fmt;
int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10;
{
	fprintf(stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
		arg8, arg9, arg10)
}

The only time that this wouldn't work is if the arguments were put on
the stack in the reverse order that they normally are in C.

			Ken Turkowski
		    CADLINC, Palo Alto
		{decwrl,amd70}!turtlevax!ken

warren@ihnss.UUCP (10/26/83)

The technique of declaring a function with the maximum number of
expected arguments and then passing them on:

foo(a1,a2,a3,a4,...an)
char *a1,*a2, ..., *an;
{
	error(errno,fmt,a1, ..., an);

DOES NOT work in all implementations.  An obvious failure occurs
when the stack isn't big enough to accomodate all of the arguments
that aren't passed to foo.  A less obvious problem that I have seen
(I forget exactly which machine it was on) is that the compiler
passes the pointer arguments using "effective address" type
instructions to get the pointer, rather than just copying the bits,
and the machine generates some sort of fault if the address in the
pointer is invalid.  Since the junk you pick up on the stack
can to be an invalid address, your code randomly fails depending
on what happens to be on the stack.

-- 

	Warren Montgomery
	ihnss!warren
	IH x2494

andree@uokvax.UUCP (10/28/83)

#R:duke:-363700:uokvax:3000004:000:438
uokvax!andree    Oct 26 08:45:00 1983

/***** uokvax:net.lang.c / turtleva!ken / 12:48 pm  Oct 24, 1983 */
The only time that this wouldn't work is if the arguments were put on
the stack in the reverse order that they normally are in C.

			Ken Turkowski
		    CADLINC, Palo Alto
		{decwrl,amd70}!turtlevax!ken
/* ---------- */
Unfortunatly, there is at least one compiler out there that does this.
Printf for this compiler is interesting (and broken) (and sickening).

	<mike

thomas@utah-gr.UUCP (Spencer W. Thomas) (10/31/83)

Re: S-1 upward growing stack.

(Of course, this depends on your hardware cooperating.)  The way I would
solve the problem would be to have the frame pointer point to  the first
argument (or, perhaps, to the word above the first argument), so that args
would be at (constant) negative offsets form the frame pointer, and local
vars would be at positive offsets.  Then you don't have a problem with
getting the wrong arg when called with the wrong number of them.

=Spencer

ggr@pyuxbb.UUCP (11/04/83)

  > Re: S-1 upward growing stack.
  > 
  > (Of course, this depends on your hardware cooperating.)  The way I would
  > solve the problem would be to have the frame pointer point to  the first
  > argument (or, perhaps, to the word above the first argument), so that args
  > would be at (constant) negative offsets form the frame pointer, and local
  > vars would be at positive offsets.  Then you don't have a problem with
  > getting the wrong arg when called with the wrong number of them.
  > 
  > =Spencer

Yes, I can testify that this scheme works fine.  I used negative offsets
for arguments in the Data General Nova/Eclipse C compiler I wrote,
since their hardware stacks also grew upward.

With appropriate modification of /usr/include/varargs.h, functions that
expect a variable number of arguments (and use varargs, of course)
will even work with this "unconventional" stack structure.

			=== Guy Riddle == AT&T Bell Laboratories, Piscataway ===

ajs@hpfcla.UUCP (11/06/83)

#R:duke:-363700:hpfcla:1500001:000:1014
hpfcla!ajs    Nov  4 15:01:00 1983

The HP9000  Series 500 also has a stack which  grows  upwards in address
space.  We attacked the variable-number-of-arguments problem this way:

1:  Push the return area first (two words).

2:  Push  the  arguments  in  reverse  order  (right  to  left),  so the
    left-most  is highest on the stack, at a known offset from the frame
    pointer.

3:  Push additional  information,  including a return area pointer and a
    number-of-arguments word.

A C program can't get to the additional  information  cleanly but it can
be done if  necessary.  Either  the  return  area  pointer  or number of
arguments may be useful.

Also, be warned that execl(2), execlp(2), and execlv(2) make assumptions
about the  order of the  arguments  (at least for  System  III).  If you
reverse that order, you have to correct the intrinsics.

(I hope this is of general  enough  interest to merit posting it instead
of responding by mail...)

Alan Silverstein, hpfcla!ajs
Hewlett-Packard Fort Collins Systems Division, Colorado

jdb@mordor.UUCP (John Bruner) (11/10/83)

Now that all of the mail has come in, here is a summary of the
responses I received to my inquiry about argument passing in C.

The consensus was that it is "legal" to implement a compiler for
which functions that do not use "varargs" must be called with the
same number of arguments with which they were defined.  This would
mean that if the 4.2BSD "open" were declared as

	open(path, flags, mode)
	char *path;
	int flags, mode;
	{

then calling it in the old way

	open("/dev/null", 0);

would be incorrect.  Although such an implementation is "legal" it
is undesirable because many programs from more permissive
environments (e.g. the VAX) depend upon this characteristic.  (One
example of this occurs in the Portable C compiler itself.)

Several people also pointed out that right-to-left evaluation of
the arguments would place the first argument at a constant offset
from the called routine's stack frame, regardless of the direction
of stack growth.  I should have mentioned in my original inquiry
that we chose left-to-right evaluation because we wanted the
arguments to be stored with ascending addresses.  Some C programs
desire this characteristic as well.

The other method for handling cases such as the one above is to use
a register as an argument pointer.  The AP points to the first
argument and all variables are referenced with positive offsets from
the AP.

We are changing the calling sequence for the S-1 compiler from one
calling mechanism (JSR/RETSR) to another one (CALL/UNCALL) that
was originally intended for another language implementation.  This
will allow us to pass an argument pointer in an efficient way.
All of the usual "tricks" with regard to argument passing in C
should then work "correctly".

Thanks for all of the help.

	John Bruner
	S-1 Project/Lawrence Livermore National Laboratory

greg@vecpyr.UUCP (Greg Millar) (04/11/86)

I have always heard that varargs is not very portable.  Is this really
true?  If you know of any machine that is running 4.X BSD, System III/V,
Xenix or any other real unix that doesn't support varargs, please let
me know.

Under AIX there are 3 functions associated with varargs called:
vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?

		
			Greg Millar

			...{ucbvax,decwrl}!dual!vecpyr!greg
			Visual Engineering, Inc.  
			2680 N. First
			San Jose, CA 95134
			(408) 945-9055

grr@cbmvax.cbm.UUCP (George Robbins) (04/12/86)

In article <272@vecpyr.UUCP> greg@vecpyr.UUCP (Greg Millar) writes:
>I have always heard that varargs is not very portable.  Is this really
>true?  If you know of any machine that is running 4.X BSD, System III/V,
>Xenix or any other real unix that doesn't support varargs, please let
>me know.
>
>Under AIX there are 3 functions associated with varargs called:
>vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?
>
>	Greg Millar {ucbvax,decwrl}!dual!vecpyr!greg
>	Visual Engineering, Inc. 2680 N. First San Jose, CA 95134

You have to define precisly what you mean by varargs...

The strict/slimey definition that works on many/most unix systems is that a
*C* function can index through its argument list in a linear fashion by taking
the address of the first argument and incrementing by the length of each
argument (which you must know or be told).  This assumes that the arguments
are all stored in some contiguous, rational order on the stack or in some
parameter block.  It is also generally assumed that a function can pass its
arguments to a function it calls, without knowing anything about them.
(frequent example: debug functions whose arguments are passed to printf)

Since these conventions are known not to work on all machines, it was decided
to create a set of 'magical' varargs routines that would allow a C program
to access it's arguments in a machine independent way.  Supposedly the
vprintf, etc. routines are reimplementations of printf, etc. that make use
of the these machine independent varargs conventions.

As you might expect, implementations where strict/slimey varargs works on the
hardware people tend to be careless about implementing/using the machine
independent form, and people who are stuck with implementations that require
the machine independent form tend to be kind of bitter about 'portable' code
created using the strict/slimey conventions.

-- 
George Robbins - now working with,	uucp: {ihnp4|seismo|caip}!cbmvax!grr
but no way officially representing	arpa: cbmvax!grr@seismo.css.GOV
Commodore, Engineering Department	fone: 215-431-9255 (only by moonlite)

ark@alice.UucP (Andrew Koenig) (04/13/86)

> I have always heard that varargs is not very portable.  Is this really
> true?  If you know of any machine that is running 4.X BSD, System III/V,
> Xenix or any other real unix that doesn't support varargs, please let
> me know.

> Under AIX there are 3 functions associated with varargs called:
> vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?

I am the author of varargs.

If you find any machine with a sensible architecture that cannot
be made to support varargs, I would greatly like to hear about it.

I also wrote the v*printf functions.  As far as I know, they are
a standard part of System V.

kalash@ingres.berkeley.edu.ARPA (Joe Kalash) (04/18/86)

>Under AIX there are 3 functions associated with varargs called:
>vsprintf, vprintf, vfprintf.  Are these only available on the IBM RT PC?
>

	These functions are available under any system that conforms
to the SVID.


			Joe Kalash
			kalash@berkeley
			ucbvax!kalash

blarson@usc-oberon.UUCP (04/21/86)

I just wrote the varargs.h header file for os9/68000 from the 4.2 BSD
documentation, (rather than hacking up the non-portable code in
microemacs) and would like a few clarifacations:

Must va_alist be the only thing in the argument list?  (If this is not
true, I don't see how to implement varargs with this compiler.)  (The
example in the documentation seems to back up my assumption.)

Is it leagal to pass a the rest of an argument list to another
function expecting it?  If so, should it be passed as a pointer to a
variable of type va_list?  (Without this capability, I supose I'll
have to document this as a non-portable use of varargs.)

I assume va_start be done in the original function.  (Dito the first
va_alist comment.)  Does va_end have to be done in the original
function also?  (va_end does nothing in my implementation.)

Thanks.  I do plan on making this available to other os9/68000 users,
preferably by talking microware into distributing it with the next
release of thier C compiler.

-- 
Bob Larson
Arpa: Blarson@Usc-Ecl.Arpa
Uucp: ihnp4!sdcrdcf!usc-oberon!blarson

ark@alice.UucP (Andrew Koenig) (04/22/86)

> Must va_alist be the only thing in the argument list?  (If this is not
> true, I don't see how to implement varargs with this compiler.)  (The
> example in the documentation seems to back up my assumption.)

Yes, va_alist must be the only thing in the argument list.  However,
you can use #define to make va_alist expand into something bigger.
That possibility, in fact, is the reason that va_alist must be the
only thing in the argument list.

> Is it leagal to pass a the rest of an argument list to another
> function expecting it?  If so, should it be passed as a pointer to a
> variable of type va_list?  (Without this capability, I supose I'll
> have to document this as a non-portable use of varargs.)

Yes, it is legal.  You may pass either a pointer to a va_list or
the entire va_list itself.  Passing the pointer is recommended, because
on some implementations the va_list may be quite large
and therefore slow to copy.  If you do pass the pointer, using
va_arg in the subroutine will advance the argument list pointer
as seen by the caller.

> I assume va_start be done in the original function.  (Dito the first
> va_alist comment.)  Does va_end have to be done in the original
> function also?  (va_end does nothing in my implementation.)

It should be.  (va_end does nothing in every implementation I've seen)

rb@ccird2 (04/25/86)

In article <5302@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes:
>> I have always heard that varargs is not very portable.  Is this really
>> true?  If you know of any machine that is running 4.X BSD, System III/V,
>> Xenix or any other real unix that doesn't support varargs, please let
>> me know.
>
>If you find any machine with a sensible architecture that cannot
>be made to support varargs, I would greatly like to hear about it.
>
The concern about about varargs is brought up in "Software Tools" by
Kernigan and Plauger.  The main concern is that certain systems and
languages have the caller push the arguments, and have the callee destroy
them when they are finished.  This is common practice in Fortran and
Pascal.  The big concern with C is that there might be a compiler out
there which has C/Pascal|Fortran compatibility.  Since these compilers
seem to be the exception rather than the rule, and newer versions of
these languages are tending to follow C conventions, this is not likely
to be a problem for *most* environments.

I have heard that there are a few "peculiar"
compilers available for the Atari ST, Mac, and Amiga, which, although
not "kosher", CAN support most varargs situations.  The problems that
can occur are "intelligent" compilers which put arguments directly
into registers rather than on the stack.  Appearantly, this can be
a real problem if you wish to "intercept" a system call at the
application side.  Why do so many of the micro operating systems
insist on putting arguments in registers!!!.  Even MS-DOS expects
arguments in registers rather than on the stack.

The C frame is a more sensible archetecture, but not the only one.
Since you specifically asked about UNIX based systems, you can be
relatively unconcerned.

There are non-portable ways to USE varargs.  The classic is to put
a long indicator into the "format argument" and pass an int. Do this
with a couple of arguments where ints are 16 bits, and longs are 32 bits,
and you will return to "never never land".  The normal usages
(printf, scanf,...) aren't usually a problem, but there are a few
"mix and match" functions using varargs which selectively mix and match
various modifiable stack addresses, and will "core dump" the whole
system.

try this: (comments are for 16 bit ints, 32 bit longs, 32 bit pointers).

main()
{
    /* top of frame = return address */
    int i;
    long l;
    scanf("%d %d",&i);	/* second argument missing, clobbers frame */
    scanf("%d",i);	/* cute "poke" of i, can demolish code or core dump */
    scanf("%ld",&i);	/* extra 16 bits is usually frame pointer or return
			   address */
    scanf("%d",l);	/* 16 bits of "garbage" plus your number possibly
			   munged beyond recognition due to byte ordering */
}

Lint will pass it, assuming printf is declared /*VARARGS*/, and the
compiler won't even sneeze.  But running it will give you "buss error
core dumped" or something equally nasty.  This is one of the few areas
where lint will not protect you.

Anyone figured out a syntax checker for these functions?
Of course, you should use a syntax checker for any of these functions.

Another cute trick I've seen is using varargs to pass integers to
functions which assign to pointers. Such as:

main()
{
    int read();
    init(0x20L,&read);	/* set exception vector */
}

/*VARARGS*/
init(a,b)
char **a,*b,**i;
{
	*a=b;	/* poke absolute value with a valid address */
}

This is the ultimate in unportability, but is frequently "hidden" in
"hostile" PC programs, typically to mount new device drivers and
remove them when the code is complete.  Just try plugging one of these
into unix unmodified :-).

grr@cbmvax (04/27/86)

In article <792@ccird2.UUCP> rb@ccird2.UUCP (Rex Ballard) writes:
>In article <5302@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes:
>>> I have always heard that varargs is not very portable...
...
>I have heard that there are a few "peculiar"
>compilers available for the Atari ST, Mac, and Amiga, which, although
>not "kosher", CAN support most varargs situations.  The problems that
>can occur are "intelligent" compilers which put arguments directly
>into registers rather than on the stack.  Appearantly, this can be
>a real problem if you wish to "intercept" a system call at the
>application side.  Why do so many of the micro operating systems
>insist on putting arguments in registers!!!.  Even MS-DOS expects
>arguments in registers rather than on the stack.

Mainly cause it makes calling subroutines very fast! (and breaks a lot of code)

imagine:	routine(arg);
		register char *arg;
		{...}

If the compiler knows that arg just happens to be in a suitable register when
the routine is called; the only overhead is an optional register to register
move, and a call instruction.  This can really speed things up when you have a
lot of little inner routines.

However, spare us compiler writers!  It just isn't worth it when you're trying
to use somebody else's 'portable' code.  It would be fine if C had nested
procedures or inlines or something, but a disaster otherwise.

>
>The C frame is a more sensible archetecture...
>

Most micro operating systems, includeing MSDOS include some degree of conceptual
compatibility with CP/M, and the CP/M system system calls were intended to be
used from assembly language programs, thus getting the arguments in registers
was easier than not.  Kind of like the influence the PDP-9 assembler had on the
selection of * and & for the C address operators, when @ and # make a lot more
sense to anybody brought up on a PDP-11.
-- 
George Robbins - now working with,	uucp: {ihnp4|seismo|caip}!cbmvax!grr
but no way officially representing	arpa: cbmvax!grr@seismo.css.GOV
Commodore, Engineering Department	fone: 215-431-9255 (only by moonlite)

mccaugh@uiucdcs.CS.UIUC.EDU (04/29/86)

It is a truism that MS-DOS prefers that arguments be passed register-wise; in
part this is due to the anticipation that the routine in question to receive

the arguments is an interrupt-routine with interrupts (hopefully) disabled,
so it must proceed about its business most hastily, less a (possibly) more
desrving interrupt get neglected.
   Some architectures -- most notably, the IBM-360/370 -- allowed for "load
multiple" and "store multiple" commands which saved the whole bank of regis-
ters in one instruction.

--Scott McCaughrin

eric@chronon (05/02/86)

In article <129@drilex.UUCP> dricej@drilex.UUCP writes:
>
>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to
>handle varargs. ...
>... Therefore, a more proper question would be: is there any
>architecture which is suitable for a C compiler, but not for varargs?

Yes!  I can think of an example close to home... An architecture with
a large (LARGE) number of registers, a sliding window to allow reference
to a smaller register set locally within a procedure, and OS support
for using the register set as a stack (handling overflow/underflow).
The first <n> arguments are passed in registers via the overlapped
sliding window, remaining have to be passed in memory.  The problem
is that no choice of <n> will be correct; you can only make arbitrarily
small the probability of it not being big enough...  and at the cost of
additional expense elsewhere...
I assert that this architecture, and the rest of what goes with this
particular feature, is particularly well-suited for efficient execution
of programs written in C.

>P.S. Microcomputers pass things in registers, rather than on the stack,
>because stack operations are slow relative to register operations.  This
>is also typical of assembly language programming, rather than C language
>programming.
>Not everybody is willing to pay the high-level language penalty.
>
>Craig Jackson
>UUCP: {harvard,linus}!axiom!drilex!dricej

Microcomputers aren't the only ones interested in the fact that using
registers is faster than using memory.  Does this argument sound RISC-y?

Note that nothing in the C language requires this particular high-level
language penalty (passing args in memory rather than in registers).
The varargs kludge is for convenience only (yes, I like it, too, and
would chafe at Pascal-like restrictiveness!).
-- 
Eric Black   "Garbage In, Gospel Out"
UUCP:        {sun,pyramid,hplabs,amdcad}!chronon!eric
WELL:        eblack
BIX:         eblack

eric@chronon (05/02/86)

Sorry, but I left out an important point from my previous posting about
vararg difficulties.

My article should in no way be construed as arguing against allowing
a variable number of arguments being passed to a called function.
Rather, it points out that code that *ASSUMES* that varargs are passed
in memory in ascending addresses *IS A HIGHLY MACHINE-DEPENDENT ASSUMPTION*
and is *NOT PORTABLE CODE*.  Library support to handle variable argument
lists in a standardized way is appropriate (see varargs.h on BSD systems
for something which comes very close).  These library routines are quite
simple on a traditional architecture (which is assumed by too many
existing pieces of code -- printf is too many already!).
-- 
Eric Black   "Garbage In, Gospel Out"
UUCP:        {sun,pyramid,hplabs,amdcad}!chronon!eric
WELL:        eblack
BIX:         eblack

ark@alice.UucP (Andrew Koenig) (05/02/86)

>   Some architectures -- most notably, the IBM-360/370 -- allowed for "load
> multiple" and "store multiple" commands which saved the whole bank of regis-
> ters in one instruction.

Of course, that one instruction almost always takes more time
(but less space) than an equivalent sequence of ordinary
loads or stores.

ark@alice.UucP (Andrew Koenig) (05/03/86)

I think people are confusing two different meanings for the same term:

	1. the practice of writing programs that accept varying
	numbers of actual parameters by declaring a single formal
	parameter, taking its address, and incrementing that
	address in various devious ways.

	2. the practice of writing programs that accept varying
	numbers of actual parameters and access them using ONLY the
	facilities provided by <varargs.h> .  The particular
	implementation of these facilities may differ from one
	machine to another.

I said I don't know offhand of a machine that can't implement #2.
I am being deluged by descriptions of machines that can't implement #1.

greg@utcsri.UUCP (Gregory Smith) (05/03/86)

In article <236@chronon.chronon.UUCP> eric@chronon.UUCP (Eric Black) writes:
>In article <129@drilex.UUCP> dricej@drilex.UUCP writes:
>>
>>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to
>>handle varargs. ...
>>... Therefore, a more proper question would be: is there any
>>architecture which is suitable for a C compiler, but not for varargs?
>
>Yes!  I can think of an example close to home... An architecture with
>a large (LARGE) number of registers, a sliding window to allow reference
>to a smaller register set locally within a procedure, and OS support
>for using the register set as a stack (handling overflow/underflow).
>The first <n> arguments are passed in registers via the overlapped
>sliding window, remaining have to be passed in memory.  The problem
>is that no choice of <n> will be correct; you can only make arbitrarily
>small the probability of it not being big enough...  and at the cost of
>additional expense elsewhere...
>I assert that this architecture, and the rest of what goes with this
>particular feature, is particularly well-suited for efficient execution
>of programs written in C.
>
I agree with your assertion. If this machine supports pointers to registers,
you could write a varargs. va_arg() would have to bump a pointer to the last
register arg to a pointer to memory, maybe by calling a 'va_bump' function.
If it doesn't support pointers to register args, then it is in a bit of
trouble with C because this is supposed to be legal:

	f(a) int a;
	{	wombat(&a);
	}
-- 
"For every action there is an equal and opposite malfunction"
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

eric@chronon.UUCP (Eric Black) (05/08/86)

Yes, this is slightly to the side of the original question as
to whether it is POSSIBLE to write a varargs() handler (a la 4.2 manpage)
for any given machine architecture, but the discussion is legitimately
moving around that target...

In article <2694@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes:
>In article <236@chronon.chronon.UUCP> eric@chronon.UUCP (Eric Black) writes:
>>In article <129@drilex.UUCP> dricej@drilex.UUCP writes:
>>>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to
>>>handle varargs. ...
>>>... Therefore, a more proper question would be: is there any
>>>architecture which is suitable for a C compiler, but not for varargs?

[I guess I answered a slightly different question here:]

>>Yes!  I can think of an example close to home... An architecture with
>>a large (LARGE) number of registers, a sliding window to allow reference
>>    [... description of register stack machine ...]
>>I assert that this architecture, and the rest of what goes with this
>>particular feature, is particularly well-suited for efficient execution
>>of programs written in C.
>>
>I agree with your assertion. If this machine supports pointers to registers,
>you could write a varargs. va_arg() would have to bump a pointer to the last
>register arg to a pointer to memory, maybe by calling a 'va_bump' function.
>If it doesn't support pointers to register args, then it is in a bit of
>trouble with C because this is supposed to be legal:
>
>	f(a) int a;
>	{	wombat(&a);
>	}
>-- 

Yup.  This is legal, and is permitted.  This machine DOES allow you
to take the address of a register, but it's an expensive feature
to support, and we'd like to get rid of it.  Other systems take care
of this at the compiler level, and it crops up with register variables,
not just arguments -- if you take the address of a variable, it can't
reside in a register, but must be copied into memory.  Possible
aliasing with pointer arithmetic gets quite hairy, but that's a
dangerous [and generally non-portable] thing to do in an undisciplined
manner.

This brings me back to my point (sort of).  This is the same problem that
other machines have with register variables and getting at them in
two different ways (by name and at the other end of a pointer).  In
the case of varargs, the "by name" is as a formal parameter, the pointer
is the usual varargs method.  Accessing varargs directly is just as
sloppy as doing something like this:
	foo()
	{
	    int a, b, *intp;

	    intp = &a;
	    *intp = 1;		/* set a to 1 */
	    intp++;
	    *intp = 2;		/* of course, this sets b to 2, doesn't it? */
	}
If you think this is good coding practice, I don't want you working
for me!  If you object to this technique, why is direct accessing of
varargs items OK?

Again, I realize this is not answering the precise question in the
original posting, but it's worth discussing.  Thanks for putting up
with me...

-- 
Eric Black   "Garbage In, Gospel Out"
UUCP:        {sun,pyramid,hplabs,amdcad}!chronon!eric

@hpislx.UUCP (05/08/86)

This message is empty.

ark@alice.UucP (Andrew Koenig) (05/10/86)

> Hypothetical but quite beleivable:  On a 68000, pass the first N
> 32-bit integer (int, long, etc.) arguements in data regisers and the
> first M (32-bit) pointer arguments in address registers.  There isn't
> a typeof operator, and the hack of determining the data type by doing
> string manipulations on the quoted type, besides preprocessor
> replacements in quoted strings being a pcc oddity, breaks when faced
> with typedefs.  (I think argument quoting via a different meathod is
> proposed in the current ansi C draft.)
>
> This is true of any architecture with different register types with
> identical size.  (Otherwise the type could be determined by sizeof,
> which I do in the varargs.h implementation I wrote.)  Any proposted
> solutions, other than not having such a compiler on such a machine?

If a pointer argument is passed in a different place from an
integer argument of the same size, then implementing varargs
requires some help from the compiler.

But such an implementation is going to have trouble in any event
because even today there are sometimes programs that forget to,
say, declare the type of an argument.  This is especially true
when that argument is merely passed to some other function.