I am used to declaring variadic functions like this:
int f(int n, ...);
When reading The C++ Programming Language I found that the declarations in the book omit the comma:
int f(int n...); // the comma has been omitted
It seems like this syntax is C++ specific as I get this error when I try to compile it using a C compiler:
test.c:1:12: error: expected ‘;’, ‘,’ or ‘)’ before ‘...’ token
int f(int n...);
Is there any difference between writing int f(int n, ...)
and int f(int n...
)?
Why was this syntax added C++?
According to § 8.3.5.4 of the C++ standard (current draft):
Where syntactically correct and where “...” is not part of
an abstract-declarator, “, ...” is synonymous with “...”.
In short, in C++ ...
(ellipsis) is an operator in its own right and so can be used without the comma, but use of the comma is retained for backwards compatibility.
Currently, both of these declarations have the same meaning:
int f(int n, ...);
int f(int n ...);
This leads to an issue where the following two declarations are both legal, yet have wildly different meanings:
template <class... T> void f(T...); // function template with parameter pack
template <class T> void f(T...); // variadic function
Once C++11 introduced variadic templates, it is much more likely that the second declaration is a programmer error rather than lazily omitting the comma. As a result, there was a proposal to remove the latter from the language (P0281), but it was apparently rejected.
With int f(int n, ...);
and int f(int n...);
, as you can see, both , ...
and ...
has the same meaning. Comma is optional.
But this int printz(...);
is valid in C++
while int printz(,...);
is not (at least one named parameter must appear before the ellipsis parameter). That's why you can have just (...)
, even though the arguments passed to such function are not accessible.
As I recall from the time, C++ indeed defined variadic function signatues as you note. Later, the rapidly evolving C language (on the journey from K&R to ANSI) introduced prototypes or new-style function declarations that also declared parameters inside parens after the function name. But, with two notable differences: the comma before the ellipses, and the need for the abomination of (void)
to indicate an empty parameter list (to preserve backward compatibility of the empty parens as an old style declaration).
Looking through my archives, I find The C++ Programming Language original edition "reprinted with corrections July 1987" shows:
argument-declaration-list:
arg-declaration-listopt ...
opt
arg-declaration-list:
arg-declaration-list ,
argument-declaration
argument-declaration
There is no form to accept the now-optional comma. Note that the arg-declaration-list is a comma-separated and this doesn't hang out to provide a comma after the list and before the next (different) thing.
This is the most natural way to write this. If you want a comma, you need explicitly , ...
in the first production, as two distinct (possibly whitespace separated) tokens.
As C's efforts to proper standardization progressed, C++ compilers started accepting the C versions as well to allow easy use of the C standard header files.
Why did the C designers add the comma when it implies a less sensible grammatical role of the ellipses as a fake parameter placeholder? I never found out.