In article <1112164544.591934.92840@o13g2000cwo.googlegroups. com>
Peter Nilsson <airia@acay.com.au> wrote:[color=blue]
>The difficulty lies with implementing [variable arguments with[/color]
no fixed argument before the first variable argument].[color=blue]
>C++ allows it, but C++ can identify calls to such functions since
>it requires function prototypes to be in scope.[/color]
C requires function prototypes to be in scope for all variadic
function calls too, so it would have been possible.
[color=blue]
>... Certainly, having two forms of va_start() would be a
>pain.[/color]
Before the 1989 standard, there was only one form of va_start,
and it took only one argument:
int like_printf(va_alist)
va_dcl /* note: no semicolon here */
{
va_list ap;
char *fmt;
va_start(ap);
fmt = va_arg(ap, char *);
vprintf(fmt, ap);
va_end(ap);
}
This would have been 100% forwards-and-backwards compatible
by including these, either in <stdarg.h> or in the old <varargs.h>
header:
#define va_alist ...
#define va_dcl /* nothing */
which would have expanded to the C99 prototype:
int like_printf(...) { va_list ap; /* and code */ }
Instead, the X3J11 committee not only stole the new "..." syntax
from C++, they also changed va_start to take *two* arguments.
[color=blue]
>Arthur J. O'Dwyer wrote:[color=green]
>> The standard just arbitrarily disallows such constructions.[/color][/color]
[color=blue]
>Given my points above, I doubt it was _arbitrarily_ disallowed.[/color]
I think it *was* arbitrary -- at least "95% arbitrary" anyway.
Note that any existing C compiler vendor had to change their
compiler to accept the new ", ..." token-sequence, in order
to handle the new prototypes:
int like_printf(const char *fmt, ...);
The "at least one fixed argument" requirement did, however, allow
them to make only the one single change to their compilers, instead
of TWO (*gasp*, horrors!), yes TWO whole changes. Suppose that,
instead of the "two arguments to va_start" change, the C89 folks
had left the existing <varargs.h> syntax alone, merely adding the
"..." ellipsis syntax for prototypes. Suppose further that they
were to declare that "the va_start macro sets up its va_list argument
to access the variable arguments". How would compiler-writers
implement this? Well, there are at least two obvious ways:
/* Method A */
#define va_start(ap) __builtin_va_start(ap)
/* Method B */
#define va_start(ap) ((ap) = &...)
Either one requires a second change to the compiler: With Method A,
the compiler needs to recognize __builtin_* functions (as gcc does).
With Method B, the compiler needs to allow unary "&" to be applied
to "..." in variable-arguments functions.
Neither of these is at all difficult in real, practical compilers.
In particular, Method B is trivial to implement in real compilers
that currently use some variation on:
#define va_start(last, ap) ((ap) = (char *)&last + sizeof last)
(A number of real compilers really do just this. Not only is it
easy -- just add "&..." as a production rule to your grammar, and
do the obvious thing in the code-generation step -- it eliminates
the problem that occurs when "last" is a narrow argument, so that
sizeof(last) needs adjusting.)
The at-least-one-fixed-argument rule would now be allowed, but
*not* *required*, because the va_start() macro would not need the
name of the last argument. This would also remove the opportunity
for the programmer to supply the wrong name, i.e., it would prevent
bugs.
Unfortunately, we are now stuck with the inferior (and incompatible
with K&R-style <varargs.h>) design, and the "at least one fixed
argument" rule. The flaw is minor, like so many of C's other little
flaws, but it is still a flaw.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.