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.