Path: utzoo!yunexus!geac!syntron!jtsv16!uunet!lll-winken!lll-tis!ames!haven!mimsy!chris
From: chris@mimsy.UUCP (Chris Torek)
Newsgroups: comp.lang.c
Subject: Re: Syntax of function prototypes...
Message-ID: <13114@mimsy.UUCP>
Date: 20 Aug 88 01:57:08 GMT
Article-I.D.: mimsy.13114
References: <8808171403.AA05181@ucbvax.Berkeley.EDU> <6105@venera.isi.edu> <4165@adobe.COM>
Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742
Lines: 98

In article <4165@adobe.COM> burgett@steel.COM (Michael Burgett) writes
[in re `int foo();' as a `prototype' declaration]:

>By function prototyping you have to declare the type and number (or
>indicate that there is a variable number) of parameters ....

Right: the key is that while `int foo();' *is* a function declaration,
it is *not* a /prototype/ declaration.

>If this [form of declaration] is used with ANSI I believe the 
>compiler will look at the first time you use a function to determine the 
>arguments...

Any compiler that does this implements none of the draft proposed
American National Standards for C.  The declaration

	int foo();

is morally equivalent to the prototype declaration

	int foo(...);

although the latter is in fact illegal.

Aside: I think this illegality is a mistake, though a minor one.
Consider the `tovector' function, which counts the number of valid
pointers passed to it and constructs a vector holding this list, then
passes the vector as an argument to a function.  It is called as
`tovector([optional PTR arguments], (PTR)NULL)'.  Here it is in `old
C', slightly compressed vertically:

	typedef char *PTR;	/* generic pointer type */
	#define	NULL	0
	#include 
	char *malloc();

	PTR *tovector(va_alist) va_dcl {
		int veclen;
		PTR *v, *p;
		va_list ap;

		/* find the vector length, including the NULL */
		va_start(ap);
		veclen = 0;
		do veclen++; while (va_arg(ap, PTR) != NULL);
		va_end(ap);
		/* create the vector */
		v = (PTR *)malloc((unsigned)veclen * sizeof(PTR));
		if (v == NULL) return (NULL);
		va_start(ap);
		for (p = v; (*p++ = va_arg(ap, PTR)) != NULL;) /* void */;
		va_end(ap);
		return (v);
	}

This is reasonably straightforward.

Here it is again, this time in dpANS C:

	typedef void *PTR;	/* generic pointer type */
	#include 
	#include 

	PTR *tovector(PTR firstarg, ...) {
		int veclen;
		PTR *v, *p;
		va_list ap;

		/* find the vector length, including the NULL */
		veclen = 1;
		if (firstarg != NULL) {
			va_start(ap, firstarg);
			do veclen++; while (va_arg(ap, PTR) != NULL);
			va_end(ap);
		}
		/* create the vector */
		v = (PTR *)malloc((unsigned)veclen * sizeof(PTR));
		if (v == NULL) return (NULL);
		p = v;
		*p++ = firstarg;
		if (firstarg != NULL) {
			va_start(ap, firstarg);
			while ((*p++ = va_arg(ap, PTR)) != NULL) /* void */;
			va_end(ap);
		}
		return (v);
	}

Notice that this time the code must be littered with special
tests for the first argument.

Certainly this is a rare case: most varargs appear after 1, 2, or
even more fixed arguments, and this problem does not arise.  But
it is not a nonexistent case, and the inelegance of disallowing
no fixed arguments is at least inconvenient.  (How is that for a
sentence full of negatives? :-) )
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris