Path: utzoo!attcan!uunet!cs.utexas.edu!wasatch!uplherc!esunix!bjones From: bjones@esunix.UUCP (Ben Jones) Newsgroups: comp.lang.c Subject: Variable length argument list handling Message-ID: <1441@esunix.UUCP> Date: 16 Aug 89 22:19:57 GMT Organization: Evans & Sutherland, Salt Lake City, Utah Lines: 111 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 andcast 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 . Each call to "var_arg" reduces this count appropriately. For example: /* = 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