[net.lang.c] Varargs in C

pedz@smu.UUCP (08/24/84)

#N:smu:13800005:000:4044
smu!pedz    Aug 24 14:07:00 1984

I had an idea for the variable arguments problem.  I hesitate
writing about my idea in this news group because I am not
advocating it as an addition to C.  I am one of those people who
believe that if it aint broke, don't fix it.  C ain't broke (to
me).  In any case, I have not really finallized my ideas so if
they seems sketchy, it is because they are.

The basis of the concept lies with a special data structure
which I will call "stack_frame".  Closely associated with the
"stack_frame" data structure is a "stack_frame_ptr" which is a
pointer to a stack_frame.  Toss in one more item which would be
included as part of stdio.h which is a function (or macro) which
I will call "get_arg".  Now here is how you use it.

First, let me say that the stack_frame will be a primitive type
much like int, or char.  Thus it could be put into a structure
BUT it would either be considered very bad practice or be
defined not to work.  The reason of couse is because a
stack_frame is not of fixed sized, thus it would cause heaps of
problems.  The reason that I have given a name at all is mostly
for describing the concept.

Instead, a stack_frame_ptr would and could be used as a type of
variable or field in a structure.  Care must of course be taken
to be sure that the stack_frame that the stack_frame_ptr points
to does not go away.  Thus the stack_frame_ptr would be used
mostly as arguments to functions called from within the function
which has the stack_frame that the stack_frame_ptr is pointing
to.

The function call which uses this technique would not do anything
special.  Thus all of the C programs written would not have to
be changed (because almost all of them use printf).  The
declaration of the function which is called with variable
arguments would be something like

foo(s)
stack_frame	s;
{
	stack_frame_ptr	temp = &s;
...
}

Obviously the stack_frame_ptr could be written as
stack_frame *temp
if you would prefer.  

At the time of the call, the address of s would be given the
address of the first argument of the function call.  Thus the &s
above would not be a specail case.  This will probably cause the
compiler to stack the arguments in reverse, but most compilers
do that at the present time anyway.

To access the arguments a person would do something such as
	int		i = next(temp, int);
	char	*s = next(temp, char *);
	...

where the first argument is a stack_frame_ptr and the second
argument is the same as that for a type case or a sizeof
arguement.  The next function/macro could probably be
implemented with a reasonable straight forward use of type casts
and incrementing the pointer by the sizeof the second argument.
There may be a need for a special operator for the pointer to
deal with alignment problems.

This is fundamentally the same as the varargs used in 4.2 but is
slightly different in that a pointer to the current stack frame
can be passed to another function.  The reason I feel that this
is important is because of the printf/_doprint type use where
printf stacks a few more arguements and then calls _doprint
because it knows how the stack frame looks and is assured that
will work (on 4.2).  But in general it would be much better to
call _doprint with a few arguements, one of which is a pointer
to the stack from of printf.  This could be done with confidence
of portability.

Note that there are two items which I have not included in this
specification.  One is a simple method of getting the number of
arguements passed.  The other item is a method of determining
the types of the arguements passed.  I feel that both of these
are bad since they force the information to be passed around all
of the time.  The method described is a more primitive,
fundamental method which could be argmented by the programmer to
support either or both of the features above.

Well, those are my thoughts.  You my have noticed that I slipped
into the mode of describing this as if is was to be added to C
but that was mostly for clearity and brevity.  Let me know what
you think.

Perry
convex!smu!pedz

ark@rabbit.UUCP (Andrew Koenig) (08/29/84)

Perry (convex!smu!ppedz) proposes a way of handling variable
argument lists that he says is better than <varargs.h> because
it allows a stack frame to be passed to a subroutine.  Well,
so does <varargs.h>!  It is permissible to say, for example:

	#include <varargs.h>

	f (va_alist) va_dcl
	{
		va_list args;
		va_start (args);
		g (&args);
		va_end (args);
	}

	g (a) va_list *a;
	{
		int arg1;
		arg1 = va_arg (*a, int);
	}

<varargs.h> does not have any way of finding out the number
of arguments because it is extremely difficult to do that
in some implementations.

kpmartin@watmath.UUCP (Kevin Martin) (08/29/84)

>This is fundamentally the same as the varargs used in 4.2 but is
>slightly different in that a pointer to the current stack frame
>can be passed to another function.
I think the 4.2 varargs does let you pass such a pointer to another
function. You declare the callee as accepting a parameter of type
'va_list', and it should be able to use this variable just like the
variables of type 'va_list' in the original (varargs) function.

>Note that there are two items which I have not included in this
>specification.  One is a simple method of getting the number of
>arguements passed.  The other item is a method of determining
>the types of the arguements passed.  I feel that both of these
>are bad since they force the information to be passed around all
>of the time
>Perry
>convex!smu!pedz

Many stack implementations already support an argument count of some
sort. Sometimes it is an actual word or byte count. Other times, it is
the count of passed values (i.e. a large struct passed by value only counts
as one). The way to use this portably is to have some way of testing
the pointer-to-next-arg for being beyond the last argument, sort of like
an eof function.
As for type information for each argument, it is not clear that this is
useful in most cases... The callee would either ignore it, or blow up if
it is wrong (at great expense of decoding the type info...).

Basically, there is a vast difference between the ratios of
(cost of implementation + cost of use) :: advantage of feature
for having an arg count and for having arg type info.
                       Kevin Martin, UofW Software Development Group

phil@RICE.ARPA (09/02/84)

From:  William LeFebvre <phil@RICE.ARPA>

> As for type information for each argument, it is not clear that this is
> useful in most cases... The callee would either ignore it, or blow up if
> it is wrong (at great expense of decoding the type info...).

What about arguments of different sizes?  On a VAX, everything is
passed on the stack in four bytes, except for floating point numbers
(such as a "double").  If your stack frame tells you the number of
bytes that were passed to a routine, you would still not be able to
tell how many arguments were passed, because you don't know the size of
each argument.  The type information would tell you.  In fact, even if
you had both the number of bytes and the number of arguments, you still
wouldn't be able to pull out the appropriate arguments in all cases.
As an example, if the caller passes an int and a double, the function
still won't know which order they were passed in, despite the fact that
he knows that there are 2 arguments and 12 bytes.

                                William LeFebvre
				Department of Computer Science
				Rice University
                                <phil@Rice.arpa>

pedz@smu.UUCP (09/03/84)

#R:smu:13800005:smu:13800006:000:940
smu!pedz    Sep  3 13:18:00 1984

RE: William LeFebrev (sp?)  William comments that without passing
some sort of type information, then it is not possible, even when
the number of arguments AND their total size is passed, to determine
the sizes/types of all of the arguments.

You comments are correct but it is possible for the programmer to pass
an additional argument (probably the first) which contains the information
he desires in the format that he feels is best.  For example, printf
passes this information implicitly with the format string.  But
execl does not pass this since it assumes that everything on the stack
is a string.  It only needs the "count" which is done by appending
a trailing zero.  Thus this information is not always needed.

I feel that since the information is not always needed AND it is possible
for the programmer to implement a type passing mechanism (and count) then
it should not be part of the language.

Perry Smith
convex!smu!pedz