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