[net.lang.c] A stupid way to do variable # of arguments?

haapanen@watdcsu.UUCP (Tom Haapanen [DCS]) (08/22/84)

<.^.>

I missed a part of the discussion on variable arguments, so maybe my
idea isn't new.  Even more likely it's awkward and maybe even
impossible.  However, here goes:

- Specify a reserved word, maybe `varargs'.

- When you wish to call a variable argument function, do something
like:

int i, j;
float x, y;
long l;
...
foo(varargs, i, x, l, y, ..)

- When you declare foo, do:

foo(argp, argv)
char *argp;
char *argv[];
{ ...

- OK, so what will happen here is that the 'varargs' tells 'C' that
this is a special case.  What 'C' will do upon calling the function is
set up an array of pointers to the parameters (in argv), as well as a
descriptor string (in argp).  The argp string could be of printf/scanf
type, or it could just be a string of single character descriptors
(f=float, d=double, i=int, l=long, c=char).  Naturally, the called
function would stilll have to do some processing to pull out the
parameters, but it would be easier than it is now.  You'd also have to
typecast each element of the pointer array, I guess.

Can anybody tell me (preferably by mail) why this would never work
(besides being clumsy)?  Thanks.


	Tom Haapanen
	University of Waterloo
	{allegra,decvax,ihnp4}!watmath!watdcsu!haapanen
	-----
	I never claimed I understood anything...

warren@tikal.UUCP (09/06/84)

There is obviously one reasonable way to handle varargs, but it requires
a language extension similar to the one proposed by Tom Haapanen, that is,
make varargs a part of a function type:

	The function itself:

	varargs char * printf (argc, argv)... /* Just like main */
		/* Note it would NOT be safe to assume that a null pointer
		 * exists at the "end" of the list unless this were in the language
		 * definition...
		 */

	When using the function:

	extern varargs char * printf ();	/* variable number AND type   */

	The CODE GENERATED by the compiler for the call to printf (my example)
	will be drastically different because of the varargs definition.  For
	example, it will push arguments (R to L) then push the array of pointers
	and then argv and lastly argc.  This is costly in stack space, it is
	true.  

	This has the additional benefit of letting the compilers know that
	other routines are NOT varargs, so they can generate better code for
	them.  In particular, they can pop the calling arguments off in the
	called routine.  On many machines this entails no additional instructions
	in the called routine, and at least one less per call.

	This is not a full answer, because on some machines, a pointer
	to one beast is a different length than a pointer to another. 
	Another layer of pointers and an argvv (argv squared ?) hurts too
	much to consider, but probably would work on those machines where
	all pointers to all the different pointers are the same size.

	All we've really done is suggest that it is impossible to create a
	programming language that is both complete and correct...
	That is, portable and usable.


	As long as I'm twiddling the semantics of the language, I'd like to
	propose "register" functions like these:

		static register int func (arg, arg2) {...}
		static register void func ....

	The purpose of the "register" (even for void !) is to prevent the
	programmer from taking the address of the function.  This allows
	the compiler to optimize function calls on some machines, where
	a near or short subroutine call could be used for those routines
	strictly local to the file, if the code size permits it.  On some
	machines, the called routine must do a short or long return, depending
	upon how it was called.  This works well together with the optimization
	mentioned above.

			teltone!warren