[comp.lang.c] Variable length argument list handling

bjones@esunix.UUCP (Ben Jones) (08/17/89)

This  discussion  relates  to the handling of variable length argument 
lists in C.

Question:  Why can't a C function which allows a  variable  number  of
arguments find out how many arguments were actually passed?

The ANSI standard for C as described in K&R-2 includes  a  method  for
using  a  variable number of arguments in a function call ("stdarg.h")
which  is  similar  to  other  methods  currently  in  use  (such   as
"varargs.h")  but  makes  no  provision  for  obtaining  the number of
arguments.  We are dependent on the caller specifying something in the
first  argument which indicates how many arguments are to follow, like
the format string in "printf".

The VAX/VMS  version  of  "varargs.h"  provides  for  a  macro  called
"va_count" which obtains the number of longwords in the argument list.
This is not quite a parameter count but it is probably the  best  that
can  be  done  since  parameter  lists  can  have  mixed  integer (one
longword) and floating point (two longwords) arguments.  In any  case,
this  feature  is  available  on the VAX because the procedure calling
standard requires a  parameter  list  to  start  with  the  number  of
longwords.   In  fact, the CALLS instruction uses this standard to pop
the parameter list off the  stack  automatically  when  the  procedure
returns.

Most other processors don't have anything special  when  it  comes  to
procedure  calling  and  so  it  is  entirely  up  to the software how
procedures are called.  Compilers for RISC processors  generally  pass
the  first  several  arguments in registers for the sake of efficiency
and they may have their choice of separate floating point and  integer
registers.   This  complicates  the  use  of  variable  argument lists
because the function itself must know what  possible  combinations  of
registers  and  stack frame variables may be utilized by the caller of
the function.

It may be possible to fake a "va_count" on those  processors.   Sun  3
has  an  instruction following the function call which pops the stack.
Sun 4 and MIPS do not pop the stack but they  consistently  store  the
last  actual  parameter  in  the instruction preceeding the call.  The
"va_count" function  would  have  to  do  some  instruction  decoding.
Still,   it   would  be  preferable  to  come  up  with  a  clean  and
non-implementation dependent mechanism.

ANSI C does not change any of the function  calling  conventions.   It
cannot  or  else existing function libraries would be invalidated when
switching to ANSI C.  Therefore, it would appear that the best way  to
get  the  length of the argument list is to add a new reserved word to
the language to handle variable parameter lists.

       -------------------------------------------------------

Just in case nobody has thought of anything better, consider offer the
following suggestion:


A function is declared the same as it is in ANSI C  but  using  a  new
reserved name:

    type funct(var_arguments);

         When "var_arguments" occurs in  a  function  declaration,  it
         indicates  that  when the function is called, parameters will
         be passed on the stack with the top of the  stack  containing
         the size of the parameter list.  Otherwise, parameters are to
         be passed according to whatever convention is currently used.

Inside the  function  code,  an  internal  pointer  of  some  sort  is
initialized  upon entry.  The following reserved functions can be used
within the body of a variable function to obtain the actual arguments:

    var_start();

         Reset the internal pointer to the start of the argument list.
         This   should  be  the  first  executable  statement  in  the
         function.


    var_arg(type)

         Get the next element  and  <type>  cast  it.   Increment  the
         internal  pointer  appropriately.  If the end of the argument
         list has been reached, trap to an error handler.


    var_count(type)

         Return the count of the number of elements remaining assuming
         that  they  are  all  of  a  certain  <type>.   Each  call to
         "var_arg" reduces this count appropriately.

For example:

    /*  <value> = maximum(p1,p2,p3,...)                 */
    /*      Return the argument with the highest value  */

    double maximum(var_arguments)
    {
    double m;
        var_start();
        m = var_arg(double);
        while (var_count(double)) m = max(m,var_arg(double));
    }


Ben Jones
Evans & Sutherland Computer Corporation
600 Komas Drive Salt Lake City, Utah 84108
(801)-582-5847 x3361
{decwrl ! utah-cs}!esunix!bjones

chris@mimsy.UUCP (Chris Torek) (08/18/89)

In article <1441@esunix.UUCP> bjones@esunix.UUCP (Ben Jones) writes
[in carefully right-adjusted text, which is then hard to read; I
have deleted the extra right-adjusting spaces]:
>Question:  Why can't a C function which allows a variable number of
>arguments find out how many arguments were actually passed?

This proposal comes up at least once a year.

The answer is: (a) no one does it now, and (b) it is not terribly
useful, so it has not been standardised.

>The VAX/VMS version of "varargs.h" provides for a macro called
>"va_count" which obtains the number of longwords in the argument list.
>This is not quite a parameter count but it is probably the best that
>can be done since parameter lists can have mixed integer (one
>longword) and floating point (two longwords) arguments.

This demonstrates one of the basic problems with `how many arguments
did I get?': it does not answer the question `what kind of arguments
did I get?'.  In this case, the two answers are mixed together (shaken,
not stirred) and about 1/2 of the result is poured out.

>In any case, this feature is available on the VAX because the
>procedure calling standard requires a parameter list to start with the
>number of longwords.  In fact, the CALLS instruction uses this standard
>to pop the parameter list off the stack automatically when the
>procedure returns.

This longword-count is, however, restricted to a maximum of 255.
Thus, if I write

	struct huge { int a[10000]; } h;
	...
	var_args_function(h);

the va_count function will probably return (10000%256), or 16.  Not
what I had in mind!  The 4BSD PCC correctly pops the ten thousand
longwords off the stack on return, and VAX gcc does as well.  Gcc, in
fact, goes so far as to use 0 as the count of longwords when the count
overflows, which would lead var_args_function to think no arguments
were passed!

>... it would appear that the best way to get the length of the argument
>list is to add a new reserved word to the language to handle variable
>parameter lists.

If nothing else, you have at least thought quite a bit harder about
the suggestion than most people who post it, because this is in fact
true.

>Just in case nobody has thought of anything better, consider offer the
>following suggestion:

`consider offer'?  `I offer', perhaps?

[definition deleted; see the original article]

Why not go all the way and require the caller to pass the types of each
argument, as well?  This would enable implementations to check the
arguments to printf(), for instance.  (It would have more overhead.)

Note also that the only way to get this in a future standard for a
language that is almost but not entirely unlike C ( :-) ---at least, if
the C languages follow in FORTRAN's footsteps) is to go out and
implement it yourself, and soon.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

henry@utzoo.uucp (Henry Spencer) (08/19/89)

In article <1441@esunix.UUCP> bjones@esunix.UUCP (Ben Jones) writes:
>Question:  Why can't a C function which allows a  variable  number  of
>arguments find out how many arguments were actually passed?

Historically, because on many machines there is no way for the callee
to figure this out without the caller explicitly passing an invisible
parameter.  Such parameters are expensive when every function call has
to include one.

Nowadays the efficiency impact could be mitigated somewhat by doing it
only for varargs functions, since ANSI C requires the varargsness of
a function to be known at the call site.

>It may be possible to fake a "va_count" on those  processors.   Sun  3
>has  an  instruction following the function call which pops the stack.
>Sun 4 and MIPS do not pop the stack but they  consistently  store  the
>last  actual  parameter  in  the instruction preceeding the call...

A lot of this is very dependent on the details of the compiler, and is
not guaranteed by the architecture.  To say nothing of what happens when
you start doing inter-language calls.  Don't forget that instruction space
may not be readable at all for an ordinary program.

It doesn't seem to be useful enough to be worth the trouble.
-- 
V7 /bin/mail source: 554 lines.|     Henry Spencer at U of Toronto Zoology
1989 X.400 specs: 2200+ pages. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/19/89)

In article <1441@esunix.UUCP> bjones@esunix.UUCP (Ben Jones) writes:
-Question:  Why can't a C function which allows a  variable  number  of
-arguments find out how many arguments were actually passed?  ...
-ANSI C does not change any of the function  calling  conventions.   It
-cannot  or  else existing function libraries would be invalidated when
-switching to ANSI C.

You answered your own question.

-Therefore, it would appear that the best way to get  the  length of
-the argument list is to add a new reserved word to the language to
-handle variable parameter lists.

X3J11 thought that the best way was to give a function that needed
that information an extra parameter containing it, when you design
its interface.