[comp.lang.c] Variable argument lists.

bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) (05/11/88)

       Does anybody know (or care) why in ANSI standard C when 
       using a variable length argument list, there is no way to 
       determine how many arguments where passed into the function?
       Without such a feature it seems to me that the most of the 
       power of the variable argument list is wasted.  In VAX C there
       is a macro called va_count.  Why is such a macro missing
       from the ANSI standard?   

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/11/88)

In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) writes:
>       Does anybody know (or care) why in ANSI standard C when 
>       using a variable length argument list, there is no way to 
>       determine how many arguments where passed into the function?
>       Without such a feature it seems to me that the most of the 
>       power of the variable argument list is wasted.  In VAX C there
>       is a macro called va_count.  Why is such a macro missing
>       from the ANSI standard?   

Requiring support for this on all functions, or even just on all
variadic functions, would add overhead that is complete waste for
the majority of applications.  There is nothing (except possibly
laziness) that keeps you from passing an explicit argument count
as the first parameter.

chris@mimsy.UUCP (Chris Torek) (05/11/88)

In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu
(Cary Bates) writes:
>Does anybody know (or care) why in ANSI standard C when 
>using a variable length argument list, there is no way to 
>determine how many arguments where passed into the function?

Simple: it cannot be done on (some|many|most) architectures.

>In VAX C [by which I presume he means some version of VMS C] there
>is a macro called va_count.

I would bet that it does not work.  Try:

	int f(int x, ...) { return va_count(); }
	int main() {
		printf("%d\n", f(0, (double)0, (double)0));
		return 0;
	}

Chances are the program will print either 5 or 4.  Neither is
correct.

>Without such a feature it seems to me that the most of the 
>power of the variable argument list is wasted.

Not so.  The printf() and exec() families, for instance, can be
implemented without va_count(): the information is found some other
way, by finding `%'s in printf formats and by finding nil pointers in
exec arguments.  In particular, printf % formats convey type
information as well; without this, variadic functions that have
variable argument types (as well as or in place of variable number of
arguments) cannot be implemented even *with* va_count.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

jnh@ece-csc.UUCP (Joseph Nathan Hall) (05/11/88)

In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) writes:
>
>       Does anybody know (or care) why in ANSI standard C when 
>       using a variable length argument list, there is no way to 
>       determine how many arguments where passed into the function?

That's because in theory one of the "fixed" arguments in your function's
argument list should indicate, either directly with a count, or indirectly
(like printf), how many arguments follow in the variable-length portion
of the argument list.


-- 
v   v sssss|| joseph hall                      || 201-1D Hampton Lee Court
 v v s   s || jnh@ece-csc.ncsu.edu (Internet)  || Cary, NC  27511
  v   sss  || the opinions expressed herein are not necessarily those of my
-----------|| employer, north carolina state university . . . . . . . . . . . 

lvc@tut.cis.ohio-state.edu (Lawrence V. Cipriani) (05/11/88)

In article <14139@brl-adm.ARPA>, bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) writes:
> 
>        Does anybody know (or care) why in ANSI standard C when 
>        using a variable length argument list, there is no way to 
>        determine how many arguments where passed into the function?

In this example (with <varargs.h>) I scan the argument list
twice.  Once to get a count, the next to do the real work.
Something similar should work in ANSI.  Can anyone tell me
if I'm wrong (again! :-( ).  This assumes all the arguments
are char* but it could be changed for a fixed number leading
args and a variable number of other things.

#include <varargs.h>

splat(va_alist)
	va_dcl
{
	va_list ap;
	register unsigned cnt = 0;
	int something;
	char *pi;

	va_start(ap);	/* arg setup */

	while ((pi = va_arg(ap, char *)) != (char *)0)
		cnt++;

	va_end(ap);	/* arg cleanup */

	va_start(ap);	/* arg setup again */

	...whatever...

	va_end(ap);	/* arg cleanup again */
	return something;
}
-- 
Larry Cipriani, AT&T Network Systems and Ohio State University
Domain: lvc@tut.cis.ohio-state.edu
Path: ...!cbosgd!osu-cis!tut.cis.ohio-state.edu!lvc (weird but right)

g-rh@cca.CCA.COM (Richard Harter) (05/11/88)

In article <11435@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>(Cary Bates) writes:
>>Does anybody know (or care) why in ANSI standard C when 
>>using a variable length argument list, there is no way to 
>>determine how many arguments where passed into the function?

>Simple: it cannot be done on (some|many|most) architectures.

>>In VAX C [by which I presume he means some version of VMS C] there
>>is a macro called va_count.

>I would bet that it does not work.  Try:

>	int f(int x, ...) { return va_count(); }
>	int main() {
>		printf("%d\n", f(0, (double)0, (double)0));
>		return 0;
>	}

>Chances are the program will print either 5 or 4.  Neither is
>correct.

??????

This seems unreasonable -- if such a gismo is part of VAX C (which
is what DEC calls it) and it were my job to implement it, I would
reserve space on the stack for the count and have the compiler
generate code to load the count onto the stack.  The argument count
is available at compile time, after all.  If the gismo returns the
length of the argument section of the stack then it is simply misnamed.

Offhand, this is a reasonable feature -- the cost of loading the count
on the stack in space and time is minor.  The comment that several people
have made that you should pass the count as a separate argument is not
entirely to the point.  One can think of situations where the count
may be unknown, e.g argument list is generated using preprocessor
conditionals.  Also, if you have, for some reason, long argument lists,
sitting down and counting them is a potential source of error.

Mind you, this is no spirited defense of such a feature.  I've done
quite nicely without it, and probably wouldn't use it if were standardly
available (and certainly not if it wasn't completely portable) but it
seems reasonable.
-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

ark@alice.UUCP (05/11/88)

In article <14139@brl-adm.ARPA>, bates%falcon.dnet%fermat@bru.mayo.edu writes:
 
>        Does anybody know (or care) why in ANSI standard C when 
>        using a variable length argument list, there is no way to 
>        determine how many arguments where passed into the function?

Such a facility is hard to implement in some
machine architectures without significantly slowing down
every function call, even those that don't use it.

lvc@tut.cis.ohio-state.edu (Lawrence V. Cipriani) (05/11/88)

In article <3569@ece-csc.UUCP>, jnh@ece-csc.UUCP (Joseph Nathan Hall) writes:
> In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) writes:
> >
* %       Does anybody know (or care) why in ANSI standard C when 
* %       using a variable length argument list, there is no way to 
* %       determine how many arguments where passed into the function?
* 
* That's because in theory one of the "fixed" arguments in your function's
* argument list should indicate, either directly with a count, or indirectly
* (like printf), how many arguments follow in the variable-length portion
* of the argument list.
* 

Nope.  For example, it is perfectly legal to have:

	p = cat(s1, s2, ..., sn, (char *)0);	/* pseudo C */

where all the si are strings.  There is no count passed, and there
is not a printf like format argument.  cat() can be called with
however many strings (si) you want, even 0.


-- 
Larry Cipriani, AT&T Network Systems and Ohio State University
Domain: lvc@tut.cis.ohio-state.edu
Path: ...!cbosgd!osu-cis!tut.cis.ohio-state.edu!lvc (weird but right)

nts0302@dsacg3.UUCP (Bob Fisher) (05/11/88)

In article <14139@brl-adm.ARPA>, bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) writes:
> 
> 
> 
>        Does anybody know (or care) why in ANSI standard C when 
>        using a variable length argument list, there is no way to 
>        determine how many arguments where passed into the function?

I have simply tested optional arguments equal to null/zero/whatever (depending
on type).  The compiler initializes the function's copy of the arugment
according to type class.

This means that the argument cannot pass the save value to which the field
is initialized.  It also means that EVERY time you exit the function, you
must reset the function's copy of the arugment.  The next time the function
is called, the value is still initialized if the argument is omitted.

Admittedly, I have used this technique only with the last argument in
the list.  I don't know if it will work with your compiler or if it will
be portable.

-- 
		- - - - - - - - - - - - - - - - - - - - - - - 
Bob Fisher @ Defense Logistics Agency Systems Automation Center, Columbus, OH
UUCP:		{uunet!gould,cbosgd!osu-cis}!dsacg1!bfisher
Phone:		614-238-9071     (Autovon 850-9071)

daniels@teklds.TEK.COM (Scott Daniels) (05/11/88)

In article <12948@tut.cis.ohio-state.edu> 
		lvc@tut.cis.ohio-state.edu (Lawrence V. Cipriani) writes:
>In article <3569@ece-csc.UUCP>, jnh@ece-csc.UUCP (Joseph Nathan Hall) writes:
>> In article <14139@brl-adm.ARPA> 
>>		bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) writes:
>> >
>* %       Does anybody know (or care) why in ANSI standard C when 
>* %       using a variable length argument list, there is no way to 
>* %       determine how many arguments where passed into the function?
>* 
>* (approx) ...That's because the arguments in your function's argument list 
>* should indicate, either directly with a count, or indirectly (like printf), 
>* how many arguments in the argument list.

VAX(VMS) C gives a count since DEC's call standard requires it.  Every 
procedure call in VMS should follow a standard that includes passing 
information on how many arguments there are.  For most languages, only
a "descriptor" is on the stack (a single word with both type and address
information).  For C, however, values are placed directly on the stack
(which is why a_count is off for big parameters).  Since this count is
supposed to be there for VMS, a handle on it is given to the programmer.
Similarly, since most other language implementers do not need the count,
they don't generate the code to provide it.  This saves code size, 
stack space, and running time (though not too much of any of them).  In
those environments, the cost of providing the a_count would be high: it
would be the cost implementing the count arg for very infrequent use.

Note that DEC has been tempted into violation C conventions by having 
this extra hidden parameter: their fopen works normally only if you
provide two arguments.  If you provide more, it presumes them to be
string specs of filesystem kinds of things.  C, however, requires
that providing too many arguments to a function not bee a problem.  I
wound up quite suprised when my code for an interpretted call that
looked like: ...(*fp)( arg[0], arg[1], arg[2], arg[3], arg[4] )...
access violated (VMS C library dereferenced the NULL following the mode
string).

-Scott Daniels (daniels@teklds.UUCP)

peter@athena.mit.edu (Peter J Desnoyers) (05/12/88)

In article <11435@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu
>(Cary Bates) writes:
>>In VAX C [by which I presume he means some version of VMS C] there
>>is a macro called va_count.
>I would bet that it does not work.  Try:
>	int f(int x, ...) { return va_count(); }
>	int main() {
>		printf("%d\n", f(0, (double)0, (double)0));
>		return 0;
>	}
>In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
>Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

As pointed out, it is VAXC, not VMS C. The VAX explicitly saves a lot
of information on the stack when it makes a subroutine call, and argument
list length is one of them. The issue of arguments of different
lengths is a tricky one - if 'f' pulls arguments off the stack as ints,
then 5 is the correct value, since that is the number it will see. If it
pulls them off as doubles, then the call is incorrect, and va_count might
not be well defined. If it is a printf-like function, then god knows
what happens. (I wish I could check my manual, but I have the 1982 version.)

.
.
.
				Peter Desnoyers
				peter@athena.mit.edu

chris@mimsy.UUCP (Chris Torek) (05/12/88)

>In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu
>(Cary Bates) wrote:
>>In VAX C [by which I presume he means some version of VMS C] there
>>is a macro called va_count.

>In article <11435@mimsy.UUCP> I replied:
>>I would bet that it does not work

(by which I meant that it is probably nargs() in disguise).

In article <5266@bloom-beacon.MIT.EDU> peter@athena.mit.edu (Peter
J Desnoyers) answers this with:
>As pointed out, it is VAXC, not VMS C.

Calling something `VAX C' or `VAX PASCAL' or `VAX FORTRAN' is a game I
refuse to play.  DEC invented it for the `VAX means VMS; VMS means VAX'
campaign.  While save in the eyes of VMS adherents those years never
really were, they have now been declared over---by Ken Olson no
less---and I think it is about time this bit of doublespeak is smashed
utterly.

>The VAX explicitly saves a lot of information on the stack when it
>makes a subroutine call, and argument list length is one of them.

But it is not.  The object stored on the stack is a ten bit field
holding the number of bytes for a `return' instruction to pop.  If the
argument list is more than 1023 bytes long, the number on the stack is
wrong.  (The Berkeley Vax compiler gets this right.  Given

	a() { struct big { int i[1000]; } big; ... f(big); }

the call f(big) compiles to this sequence:

	movc3	$4000,-4000(fp),(sp)
	calls	$232,_f
	addl2	$3072,sp

Note the addl2, which is not redundant even if the second line is
changed to

	calls	$4000,_f

It would take only 128 `double's to go over the 1023 byte limit for
`calls'/`ret'.)

>The issue of arguments of different lengths is a tricky one ....

Indeed it is.  In fact, as I cleverly obscured :-) in my previous
article (>> above), it is the heart of the matter:

[pretend the following paragraph is in boldface]

    C code is never correct if it treats values as typeless.  All
    C expressions and all C variables are represented by <type,value>
    pairs.  Ignoring the <type> part will almost certainly get you in
    trouble.

And this is the problem with va_count(): even if it uses a `hidden
argument' (something other than the return byte count), it can only
tell you how many arguments there were.  It cannot tell you their
types.  In short, it is not general enough for C.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

andrew@teletron.UUCP (Andrew Scott) (05/12/88)

In article <3080@teklds.TEK.COM>, daniels@teklds.TEK.COM (Scott Daniels) writes:
> C, however, requires
> that providing too many arguments to a function not be a problem.

Is this true, or just a fluke thing that works under many C implementations?
-- 
Andrew Scott	andrew@teletron.uucp	- or -
		{ihnp4, codas, ubc-cs, watmath, ..}!alberta!teletron!andrew

henry@utzoo.uucp (Henry Spencer) (05/12/88)

>       Does anybody know (or care) why in ANSI standard C when 
>       using a variable length argument list, there is no way to 
>       determine how many arguments where passed into the function?

Because it's costly and usually unnecessary.  On the VAX it happens to be
free, since the VAX's all-singing-all-dancing-slow-like-turtle function
call instructions give it to you.  Well, they give you a *word* count, not
an argument count, and the difference matters if you start using various
data types, but sloppy programmers ignore that.  On most other machines,
though, the only way to get a count is if the caller carefully provided
you with one.  This can add significantly to the cost of a well-tuned
function-call convention -- and that's not a trivial issue, because C
programs do *lots* of function calls.

>       Without such a feature it seems to me that the most of the 
>       power of the variable argument list is wasted...

Nonsense.  Printf and friends don't need it, because the format string
implicitly contains this information.  Execl and friends don't need it,
because their arg list is null-terminated.  Yes, there are situations
where it would be useful, but not all that many of them.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

henry@utzoo.uucp (Henry Spencer) (05/12/88)

> In this example (with <varargs.h>) I scan the argument list
> twice.  Once to get a count, the next to do the real work.
> Something similar should work in ANSI.  Can anyone tell me
> if I'm wrong (again! :-( ).  This assumes all the arguments
> are char* ...

Looks okay to me, provided that the argument list is terminated (by
the user -- the compiler won't do it for you) with a null pointer of
the correct type.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

karl@haddock.ISC.COM (Karl Heuer) (05/13/88)

In article <11453@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>[C is not typeless; its values are really <type,value> pairs; ignoring the
><type> part is dangerous.]  And this is the problem with va_count(): even if
>it uses a `hidden argument' (something other than the [VMS] return byte
>count), it can only tell you how many arguments there were.  It cannot tell
>you their types.  In short, it is not general enough for C.

It couldn't handle polymorphic functions like printf(), but it would still be
useful for monomorphic functions like execl() or multistrcat().  (Using a
sentinel at the end of the list is error-prone, and if the type in question is
not a pointer, there may not be any appropriate out-of-band value to use.
Using an explicit argcount variable is also error-prone ("Computers are much
better than humans at counting"), and nontrivial in the face of #if'd args.)

Actually, va_count() may be more powerful than we need.  We could eliminate
the problem of what the "count" really means; all we really need is a boolean
that will tell us when we're at the end of the arglist.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

ok@quintus.UUCP (Richard A. O'Keefe) (05/13/88)

In article <27794@cca.CCA.COM>, g-rh@cca.CCA.COM (Richard Harter) writes:
(somebody wrote)
> >>In VAX C [by which I presume he means some version of VMS C] there
> >>is a macro called va_count.

> If the gismo returns the
> length of the argument section of the stack then it is simply misnamed.

The DEC manual clearly says as the first sentence of 20.2.2
    "This macro returns the number of LONGWORDS in the argument list."
It explicitly warns that if your arguments aren't longword sized, you
may have to figure out for yourself how many arguments that is.

jfh@rpp386.UUCP (John F. Haugh II) (05/13/88)

In article <11435@mimsy.UUCP> chris@mimsy.UUCP writes:
>In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu
>>In VAX C [by which I presume he means some version of VMS C] there
>>is a macro called va_count.
>
>I would bet that it does not work.  Try:

[ example deleted ]

>Chances are the program will print either 5 or 4.  Neither is
>correct.
>-- 
>In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)

this function can be implemented if the C compiler uses the CALLS
instruction.  CALLS is of the form

	CALLS	#<number-of-arguments>,<where-to-go>

the number of arguments is stacked by the call instruction and can be
found (if i remember - it can be found however) by referencing the
value located at (AP).

this mechanism also works for the CALLG instruction which expects
an argument list which has been setup to include the count.  (FORTRAN
uses CALLG since the argument list can be statically allocated)  when
CALLG is executed, AP is loaded with the address provided as the
first argument to the instruction.

- john.
-- 
John F. Haugh II                 | "You see, I want a lot. Perhaps I want every
River Parishes Programming       | -thing.  The darkness that comes with every
UUCP:   ihnp4!killer!rpp386!jfh  | infinite fall and the shivering blaze of
DOMAIN: jfh@rpp386               | every step up ..." -- Rainer Maria Rilke

karl@haddock.ISC.COM (Karl Heuer) (05/14/88)

In article <300@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>In article <3080@teklds.TEK.COM>, daniels@teklds.TEK.COM (Scott Daniels) writes:
>>[C allows a function to be called with extra arguments, which are ignored]
>
>Is this true, or just a fluke thing that works under many C implementations?

It's a fluke.  (It doesn't always work, even in UNIX implementations.)  In
ANSI C, it's definitely illegal for nonvariadic functions, and explicitly
legal for the printf/scanf families.  The properties of <stdarg.h> seem to
imply that it would also be legal for any user-supplied variadic function.
That leaves non-standard vendor-supplied variadic functions, such as execl; my
guess is that it's the vendor's responsibility to document the domain.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

bts@sas.UUCP (Brian T. Schellenberger) (05/14/88)

In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) writes:
|       Does anybody know (or care) why in ANSI standard C when 
|       using a variable length argument list, there is no way to 
|       determine how many arguments where passed into the function?
|       Without such a feature it seems to me that the most of the 
|       power of the variable argument list is wasted.

Because it is not possible to do so on many architectures, including lots of
Unices.  In fact, it is not possible to determine this information with the
standard Unix varargs, either.  And printf et al have gotten along for years
without the capability.

K&R (orig) say:

printf, the most common C function with a variable number of arguments,
uses information from the first argument to determine how many arguments
are present . . . It fails badly if the caller does not supply enough
arguments.

So, in short, if VMS supplies this capablity, enjoy it.  But the rest of the 
world has gotten along without it all these years, and seems to have survived 
just fine.  Thus, I seriously doubt that it "most of the power of the
variable argument list is wasted."
-- 
 _______________________                             __Brian___________________
|Brian T. Schellenberger| "The Earth is but one     | ...!mcnc!rti!sas!bts     |
|104 Willoughby Lane    | country, and Mankind its  |work: (919) 467-8000 x7783|
|Cary, NC   27513       | citizens" --Baha'u'llah   |home: (919) 469-9389      |

henry@utzoo.uucp (Henry Spencer) (05/14/88)

> ... C, however, requires
> that providing too many arguments to a function not bee a problem...

Sorry, wrong.  C has never required or guaranteed this, and there are
machines on which it won't work.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

daniels@teklds.TEK.COM (Scott Daniels) (05/14/88)

In article <300@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>In article <3080@teklds.TEK.COM>, daniels@teklds.TEK.COM (Scott Daniels)writes:
>> C, however, requires
>> that providing too many arguments to a function not be a problem.
>Is this true, or just a fluke thing that works under many C implementations?

K&R (original) 4.3 (page 71, paragraph 4):
	"It is generally safe to deal with a variable number of arguments 
	if the called function doesn't use an argument which was not actually
	supplied, and if the types are consistent".

I take that as a constraint when writing a C compiler.  Often there are more
efficient ways of passing parameters (such as callee cleans up stack), but
that is not "the C way".

-Scott Daniels		daniels@teklds.UUCP or daniels@teklds.TEK.COM

jfh@rpp386.UUCP (John F. Haugh II) (05/14/88)

In article <7864@alice.UUCP> ark@alice.UUCP writes:
>In article <14139@brl-adm.ARPA>, bates%falcon.dnet%fermat@bru.mayo.edu writes:
> 
>>        Does anybody know (or care) why in ANSI standard C when 
>>        using a variable length argument list, there is no way to 
>>        determine how many arguments where passed into the function?
>
>Such a facility is hard to implement in some
>machine architectures without significantly slowing down
>every function call, even those that don't use it.

the addition of an extra instruction to stack the number of arguments
can hardly be considered significantly slowing down a function call.
this sounds like the anti-recursion argument IBM is so fond of - `but
stacking all those variables is SO expensive' ...

the addition of one more instruction (or two or three or whatever for
really deficient hardware) to provide such a useful function would
seem like A Good Thing.

- john.
-- 
John F. Haugh II                 | "You see, I want a lot. Perhaps I want every
River Parishes Programming       | -thing.  The darkness that comes with every
UUCP:   ihnp4!killer!rpp386!jfh  | infinite fall and the shivering blaze of
DOMAIN: jfh@rpp386               | every step up ..." -- Rainer Maria Rilke

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/16/88)

In article <1740@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:
>the addition of an extra instruction to stack the number of arguments
>can hardly be considered significantly slowing down a function call.

WRONG.  Multiply the extra cost per function call by the number of
function calls per day, to see how much computer time you would be
wasting each day.

Function call overhead is so significant that, for example, when
Gould figured out a way to save a small amount for UTX-32 Release
1.3 (I think it was), they made the change even though it introduced
an incompatibility with existing UTX-32 object code.

>the addition of one more instruction (or two or three or whatever for
>really deficient hardware) to provide such a useful function would
>seem like A Good Thing.

But it is NOT a very useful function.  There are already ways to
obtain corresponding functionality when necessary (which is almost
never), without forcing EVERY function call to pay the penalty.

The main reason ANSI C has a different syntax for variadic-argument
functions is precisely to avoid forcing a less efficient function
linkage overhead for the VAST MAJORITY of function calls.  Those
that need the service should pay the price.  Down with socialism.

henry@utzoo.uucp (Henry Spencer) (05/16/88)

> the addition of an extra instruction to stack the number of arguments
> can hardly be considered significantly slowing down a function call.

I consider it significantly slowing down a function call.  If you live
on a machine where each function call takes dozens of instructions, then
I understand your disregard for yet one more.  Some of us have machines
with efficient function calls, and we would like to keep them that way!

The real objection is to the overhead of that extra instruction when no
portable program, no standard library function, and no formal standard
has any requirement for it.  You may think it is oh-so-useful; the rest
of us have been doing fine without it for quite a while, thank you, and
don't see any reason why we should pay the price in performance.
-- 
NASA is to spaceflight as            |  Henry Spencer @ U of Toronto Zoology
the Post Office is to mail.          | {ihnp4,decvax,uunet!mnetor}!utzoo!henry

jangr@microsoft.UUCP (Jan Gray) (05/16/88)

In article <1740@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:
>the addition of an extra instruction to stack the number of arguments
>can hardly be considered significantly slowing down a function call.

Right.  Slow down every function call ever, just so you can use your
nargs() function once in a blue moon.  On machines with fast function
calls (e.g. SPARC, which typically stacks no arguments), *any* extra work
is extremely significant.

Try
	char *cat(int nargs, ...);

	cat(6, "lets", "move", "on", "to", "something", "else");

"The addition of an extra parameter to specify the number of arguments can
hardly be considered significantly slowing down a function call."

Jan Gray   uunet!microsoft!jangr   Microsoft Corp., Redmond Wash.   206-882-8080

jfh@rpp386.UUCP (John F. Haugh II) (05/16/88)

In article <504@sas.UUCP> bts@sas.UUCP (Brian T. Schellenberger) writes:
>In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) asks:

[ why can't functions with variable numbers of arguments determine the
  number of arguments they were called with? ]

>Because it is not possible to do so on many architectures, including lots of
>Unices.

could someone please present an example of an architecture were this
CAN'T be done?  and does anyone actually have timings for a system where
this has been done versus not to support the claim that doing this is
very expensive?

- john.
-- 
John F. Haugh II                 | "You see, I want a lot. Perhaps I want every
River Parishes Programming       | -thing.  The darkness that comes with every
UUCP:   ihnp4!killer!rpp386!jfh  | infinite fall and the shivering blaze of
DOMAIN: jfh@rpp386               | every step up ..." -- Rainer Maria Rilke

firth@sei.cmu.edu (Robert Firth) (05/16/88)

In article <1701@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:

>this function can be implemented if the C compiler uses the CALLS
>instruction.  CALLS is of the form
>
>	CALLS	#<number-of-arguments>,<where-to-go>

Is there no hope of correcting this misinformation?  ONE MORE TIME:
the first operand of CALLS is the NUMBER OF LONGWORDS passed in the
argument list.  It is NOT the number of arguments.

At one time, DEC tried to enforce a software convention that all
arguments would be exactly one longword in size: smaller values
would be padded, larger ones would be passed by reference, and
dynamic-sized ones would be passed by reference-to-descriptor.

This conventing is NOT obeyed by DEC system software, or by most
compilers for the VAX-11.  In general, you CANNOT assume that

	MOVZBL (AP), Reg

will give you the "number of arguments".

faustus@ic.Berkeley.EDU (Wayne A. Christopher) (05/16/88)

In article <1740@rpp386.UUCP>, jfh@rpp386.UUCP (John F. Haugh II) writes:
> the addition of one more instruction (or two or three or whatever for
> really deficient hardware) to provide such a useful function would
> seem like A Good Thing.

The number of arguments isn't the only issue, remember...  You have to know
the types too.  Ints and doubles are of different sizes.  If you know
all your arguments are of one type, though, I'll bet you could figure
out the number of arguments from within the called function for just about
any architecture.

	Wayne

firth@sei.cmu.edu (Robert Firth) (05/17/88)

In article <1777@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:

[ why can't functions with variable numbers of arguments determine the
  number of arguments they were called with? ]

>could someone please present an example of an architecture were this
>CAN'T be done?  and does anyone actually have timings for a system where
>this has been done versus not to support the claim that doing this is
>very expensive?

Glad to.  The BCPL codegenerator I wrote for the MIPS M/500 passes the
first N parameters in registers and the rest on the stack.  The called
function stores the registers (if necessary) into the correct place on
the stack.

A function has to know the maximum number of arguments it will be passed,
since it must allocate its local space above them, but it does not know
how many it has actually been passed, and cannot find out (not least
because motion of the stack pointer across successive calls is optimised).

If we consider the average function has two parameters, then the extra
cost is a (hidden) third parameter.  That raises the full call/entry/
exit/return sequence from ~10 instructions to ~12, ie an overhead of 20%.

No, I do not want to pay that price.

franka@mmintl.UUCP (Frank Adams) (05/17/88)

In article <504@sas.UUCP> bts@sas.UUCP (Brian T. Schellenberger) writes:
>Thus, I seriously doubt that it "most of the power of the
>variable argument list is wasted."

Actually, I think the original statement is correct (at least if "most" is
interpreted as "the majority of").  But variable argument lists are in the
nature of a frill, not a necessity.  Even printf could be replaced quite
adequately by a series of calls, one to output each item or bit of
intervening text.  Such a protocol seems horrible the first time you
encounter it, but after just a little experience you realize that it is not
appreciably worse than the other approach.
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

mouse@mcgill-vision.UUCP (der Mouse) (05/18/88)

In article <11453@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
>> In article <14139@brl-adm.ARPA> bates%falcon.dnet%fermat@bru.mayo.edu (Cary Bates) wrote:
>>> In VAX C [by which I presume he means some version of VMS C] [...]
> In article <5266@bloom-beacon.MIT.EDU> peter@athena.mit.edu (Peter J Desnoyers) answers this with:
>> As pointed out, it is VAXC, not VMS C.
> Calling something `VAX C' or `VAX PASCAL' or `VAX FORTRAN' is a game
> I refuse to play.  DEC invented it for the `VAX means VMS; VMS means
> VAX' campaign.  [Those years] have now been declared over---by Ken
> Olson no less---and I think it is about time this bit of doublespeak
> is smashed utterly.

(Finally, someone else who sees through this bit of propaganda!)  It's
not restricted to DEC and the net, I'm afraid.  Some magazines contain
ads talking about "<feature foo> for your VAX", but on closer reading,
the language they use makes it abundantly clear they really mean
"...for your VMS VAX".  It's soooo tempting to find one that doesn't
*say* VMS anywhere, order the product, and then complain about how it
won't install - we can't even read the distribution!  (cackle :-)

>> The VAX explicitly saves a lot of information on the stack when it
>> makes a subroutine call, and argument list length is one of them.
> But it is not.  The object stored on the stack is a ten bit field
> holding the number of bytes for a `return' instruction to pop.

It's not even that.  It's an eight-bit field containing the number of
longwords to pop.  And it should be noted that (a) there's a version of
the call instruction - callg - that doesn't use the stack for arguments
and (b) it is perfectly possible to use the bsbb/bsbw/jsb instructions
to build a calling sequence that doesn't do the song and dance that
calls/callg do.  (Why does the Berkeley assembler contain no j version
of bsbb?  Anyone know?)

> And this is the problem with va_count(): even if it uses a `hidden
> argument' (something other than the return byte count), it can only
> tell you how many arguments there were.  It cannot tell you their
> types.  In short, it is not general enough for C.

Only because it returns only one value.  There's nothing preventing a
compiler from pushing all sorts of hidden stuff describing the arglist
in detail for the subroutine.  (Nobody would be silly enough to build
such a compiler, except possibly for find-the-bug-I-don't-care-beans-
about-speed use.)

					der Mouse

			uucp: mouse@mcgill-vision.uucp
			arpa: mouse@larry.mcrcim.mcgill.edu

jfh@rpp386.UUCP (John F. Haugh II) (05/20/88)

In article <7893@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <1740@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:
>>the addition of an extra instruction to stack the number of arguments
>>can hardly be considered significantly slowing down a function call.
>
>WRONG.  Multiply the extra cost per function call by the number of
>function calls per day, to see how much computer time you would be
>wasting each day.

CORRECT.  regardless of how many function calls are made, the decrease
in time is a constant factor (when averaged out over the collection
of jobs in the mix).  if we make the assumption that PUSH, CALL and
RETURN as generic operators have similiar execution times, at worst
for an empty function you see 50% slowdown.  (i know, 50% is a lot ...)
more reasonable figures are << 10%, see the example below.

an improvement of 50% could be had by removing some of the function
calls and writing the damned thing in assembler.  furthermore, a significant
fraction of the execution time of any real world application will be
spent doing I/O of some form.  thus, any increase in CPU requirement
will be diluted when you consider the fraction of the time which
is _actually_ spent executing instructions.

thus, the actual slowdown will be somewhat less.  if you are interested
in the results for one application which i converted to use argument
counts, the demonstration is presented below.

- john.
--
the times below are for a toy i am working on which draws maps from the
location info in uucp maps.  this is the user time for processing 540
sites (east texas repeated 10 times, more or less).  the first is without
argument counts in each function, the second with.

uudraw: 11.1 seconds user		-- no argument counts.
nndraw: 11.3 seconds user		-- argument counts.

the speed penalty is ~1.8%, which as i said earlier is hardly significant.
the argument counts were implemented as

	func (n_args, arg1, arg2, ...);

for calls with

func (nargs, arg1, arg2, ...)
int	nargs;
...
{
	if (nargs != expected_number_arguments)
		abort ();
	...
}

for definitions.  the program itself is highly modular and contains a
larger number of function calls than what i would consider to be ``normal''.
thus, i suggest that the < 2% penalty is actually high.  furthermore,
since this is code which was not automatically included by the compiler,
i further suggest that this number could be reduced were the compiler
permitted to have full control over this process.

benchmarks which have been conducted show speed improvements are available
by selective use of assembler code.  the C library for this system has
assembler coded string library functions which increase the Dhrystone
benchmark rating on the order of 20%.  a paper written by dennis ritchie
himself described the performance decreases which were had as a
result of using C versus assembler in writting the unix operating system.
yet, as i recall statements were made to the effect that the advantages
of coding in C outweighed the space/time advantages of assembler.

while adding runtime checking for argument counts may not be the savior
computer science has been waiting for, it surely is not without ``prior
art'' in the form of array bounds checking, null pointer checking and
enumerated subrange checking which is performed in other languages under
various options.  as a tool for development and debugging work, why
reject it?  other tests are near impossible.  with this being so damned
cheap and easy it seems like a waste to not consider it.

- john.
-- 
John F. Haugh II                 | "You see, I want a lot. Perhaps I want every
River Parishes Programming       | -thing.  The darkness that comes with every
UUCP:   ihnp4!killer!rpp386!jfh  | infinite fall and the shivering blaze of
DOMAIN: jfh@rpp386.uucp          | every step up ..." -- Rainer Maria Rilke

raeburn@athena.mit.edu (Ken Raeburn) (05/20/88)

In article <5485@aw.sei.cmu.edu> firth@bd.sei.cmu.edu.UUCP (Robert Firth) writes:
>In article <1777@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:
>
>[ why can't functions with variable numbers of arguments determine the
>  number of arguments they were called with? ]
>
>>could someone please present an example of an architecture were this
>>CAN'T be done?  and does anyone actually have timings for a system where
>>this has been done versus not to support the claim that doing this is
>>very expensive?
>
> [....]
>
>If we consider the average function has two parameters, then the extra
>cost is a (hidden) third parameter.  That raises the full call/entry/
>exit/return sequence from ~10 instructions to ~12, ie an overhead of 20%.
>
>No, I do not want to pay that price.

How about the average number of arguments passed to variadic
functions?  They're the only ones that should need the information.

Yes, I realize that includes *printf, some of the most-used functions.
(And *scanf too, but who in their right mind uses those anyways? :->)
And the work that they do quite likely far outways the cost of an
extra argument, especially since that argument is going to be a
constant known at compile-time.  (Well, okay, I suppose anything's
possible, and I'm not familiar with too many architectures, but are
there [m]any out there that would lose big here?)

I wouldn't mind a very slight extra cost for runtime code to catch
that missing argument to printf when I goof up.

And for those who do insist on using *scanf, it's probably of greater
importance.  While printf might by chance pick up some stack garbage
or random stuff in data space, or could die by reaching outside the
address space, scanf will probably cause trouble by overwriting the
same information.

Most of the variadic functions I've seen outside of the C library are
routines that print an error message (via fprintf/_doprnt, yes I'm
using BSD) and exit with an error status.  This means that the number
of arguments winds up being ignored, though if it were available
through the language (and some v*printf interface permitted it) it
could still be used to check the argument list against the format
string.  The (machine-specific) definition of va_arg could even be
written to note immediately when the end of the argument list has been
reached (if the dpANS permits enough leeway in that particular case).

- Ken Raeburn
  MIT Project Athena

ray@micomvax.UUCP (Ray Dunn) (05/20/88)

In article <7893@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <1740@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:
>>the addition of an extra instruction to stack the number of arguments
>>can hardly be considered significantly slowing down a function call.
>
>WRONG.  Multiply the extra cost per function call by the number of
>function calls per day, to see how much computer time you would be
>wasting each day.
>
>Function call overhead is so significant that....

I'm not too happy pointing this out, but really!!

Am I totally up the wall, or is this the same person who berated me recently
for suggesting that "cdecl" in Microsoft C on the PC was A Good Thing
because amongst other things, it conveniently enabled the saving of an
instruction per function call?

From the argument above, even if that was the *only* reason for "cdecl",
then it would be A Good Thing (and it *is*)!

-- 
Ray Dunn.                      |   UUCP: ..!{philabs, mnetor}!micomvax!ray
Philips Electronics Ltd.       |   TEL : (514) 744-8200   Ext: 2347
600 Dr Frederik Philips Blvd   |   FAX : (514) 744-6455
St Laurent. Quebec.  H4M 2S9   |   TLX : 05-824090

nevin1@ihlpf.ATT.COM (00704a-Liber) (05/21/88)

In article <5451@bloom-beacon.MIT.EDU> raeburn@athena.mit.edu (Ken Raeburn) writes:
>How about the average number of arguments passed to variadic
>functions?  They're the only ones that should need the information.

>Yes, I realize that includes *printf, some of the most-used functions.
>(And *scanf too, but who in their right mind uses those anyways? :->)
>And the work that they do quite likely far outways the cost of an
>extra argument, especially since that argument is going to be a
>constant known at compile-time.

Yes, but things like *printf() have to *interpret* the first argument to
find out all the necessary info on the rest of the variables (such as
type).  Also, someone might pass to *printf() n+1 parameters and change the
format string so that only n-k parameters get printed.

>I wouldn't mind a very slight extra cost for runtime code to catch
>that missing argument to printf when I goof up.

Unless this is caught at *compile* time, I have no need or want of this
check.  What normally happens when you give it too few
arguments?  It either prints funny results or it bombs with a memory error.
What happens if the check is put in?  Very likely, the program would just
die (same thing happens in Pascal with range errors; this is one of the
primary reasons that I dislike Pascal).  The programs I write need to be
able to recover from errors.  I want good, efficient code that does not pay
a penalty because some of the people who code in C don't do it correctly.
If I can get all my printf/scanf's correct, why should I pay a penalty??

>And for those who do insist on using *scanf, it's probably of greater
>importance.  While printf might by chance pick up some stack garbage
>or random stuff in data space, or could die by reaching outside the
>address space, scanf will probably cause trouble by overwriting the
>same information.

Are there any statistics on this kind of stuff?

As you have stated, *printf is used a lot.  For this reason alone, I want
it to be as fast as possible.
-- 
 _ __			NEVIN J. LIBER	..!ihnp4!ihlpf!nevin1	(312) 510-6194
' )  )				"The secret compartment of my ring I fill
 /  / _ , __o  ____		 with an Underdog super-energy pill."
/  (_</_\/ <__/ / <_	These are solely MY opinions, not AT&T's, blah blah blah

ok@quintus.UUCP (Richard A. O'Keefe) (05/22/88)

In article <4824@ihlpf.ATT.COM>, nevin1@ihlpf.ATT.COM (00704a-Liber) writes:
> As you have stated, *printf is used a lot.  For this reason alone, I want
> it to be as fast as possible.

The best way to do that would seem to be for the compiler to macro-expand
*printf() to a sequence of simple procedure calls (when it can, which is
when the format argument is a literal, as it usually is).  Now that ANSI C
defines *printf(), a compiler may safely do so.

[I cut my computational teeth on a B6700, where the Fortran and Algol
compilers handled formats at compile-time.  It came as an unpleasant
shock to me to find that the rest of the world still interpreted them.]

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/27/88)

In article <1068@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes:
>Am I totally up the wall, or is this the same person who berated me recently
>for suggesting that "cdecl" in Microsoft C on the PC was A Good Thing
>because amongst other things, it conveniently enabled the saving of an
>instruction per function call?

I don't think you understood the objections to "cdecl", and I do not
wish to reopen that argument.  I merely note that my position on
that does not contradict my desire for maximally fast C function
linkage.