I answered this question How can I get my va_list arguments to repeat itself? and noticed the uncommon function declaration:
void ordered(int num1, double list ...);
First i thought the compiler would complain but clang 3.2 didn't and neither did g++ 4.7.2.
What does this declaration expand to? As what does it get interpreted?
Edit: I know about the ellipsis. But the normal form is <return type> <function-name>(<argument1-type> <arg-name>, ...); in the example the comma is missing.
It's the same as:
void ordered(int num1, double list, ...);
This is a snippet of the grammar in the C++ standard:
parameter-declaration-clause:
parameter-declaration-list[opt] ...[opt]
parameter-declaration-list , ...
Basically the ellipsis can be preceded by , if the are other parameter declarations, but it need not be. The function declaration:
void f(int,double...);
really means:
void f(int,double,...);
void ordered(int num1, double list ...);
is same as:
void ordered(int num1, double list, ...);
Reference:
Standard C++11 8.3.5.3/4:
parameter-declaration-clause:
parameter-declaration-listopt ...opt
parameter-declaration-list , ...
If the parameter-declaration-clause terminates with an ellipsis or a function parameter pack (14.5.3), the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument and are not function parameter packs. Where syntactically correct and where “...” is not part of an abstract-declarator, “, ...” is synonymous with “...”.
The three dots (...) are called "ellipses" and denote a variable argument list. So you can pass as many arguments as you like (there is an OS-specified limitation, though). In this way, printf works, for example.
See here for further explanation.
I guess you mean the "..." right?
For some functions it is not possible to specify the number and type of all arguments expected in a call. Such a function is declared by terminating the list of argument declarations with the ellipsis (...).
Related
Consider these two function definitions:
void foo() { }
void foo(void) { }
Is there any difference between these two? If not, why is the void argument there? Aesthetic reasons?
In C:
void foo() means "a function foo taking an unspecified number of arguments of unspecified type"
void foo(void) means "a function foo taking no arguments"
In C++:
void foo() means "a function foo taking no arguments"
void foo(void) means "a function foo taking no arguments"
By writing foo(void), therefore, we achieve the same interpretation across both languages and make our headers multilingual (though we usually need to do some more things to the headers to make them truly cross-language; namely, wrap them in an extern "C" if we're compiling C++).
I realize your question pertains to C++, but when it comes to C the answer can be found in K&R, pages 72-73:
Furthermore, if a function declaration does not include arguments, as
in
double atof();
that too is taken to mean that nothing is to be assumed about the
arguments of atof; all parameter checking is turned off. This special
meaning of the empty argument list is intended to permit older C
programs to compile with new compilers. But it's a bad idea to use it
with new programs. If the function takes arguments, declare them; if
it takes no arguments, use void.
C++11 N3337 standard draft
There is no difference.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
Annex C "Compatibility" C.1.7 Clause 8: declarators says:
8.3.5 Change: In C ++ , a function declared with an empty parameter list takes no arguments. In C, an empty
parameter list means that the number and type of the function arguments are unknown.
Example:
int f();
// means int f(void) in C ++
// int f( unknown ) in C
Rationale: This is to avoid erroneous function calls (i.e., function calls with the wrong number or type of
arguments).
Effect on original feature: Change to semantics of well-defined feature. This feature was marked as “obsolescent” in C.
8.5.3 functions says:
4. The parameter-declaration-clause determines the arguments that can be specified, and their processing, when
the function is called. [...] If the parameter-declaration-clause is empty, the function
takes no arguments. The parameter list (void) is equivalent to the empty parameter list.
C99
As mentioned by C++11, int f() specifies nothing about the arguments, and is obsolescent.
It can either lead to working code or UB.
I have interpreted the C99 standard in detail at: https://stackoverflow.com/a/36292431/895245
In C, you use a void in an empty function reference so that the compiler has a prototype, and that prototype has "no arguments". In C++, you don't have to tell the compiler that you have a prototype because you can't leave out the prototype.
In the C++03 standard, [dcl.fct] p.2 states that:
The parameter-declaration-clause determines the arguments that can be specified, and their processing, when the func- tion is called. [ Note: the parameter-declaration-clause is used to convert the arguments specified on the function call; see5.2.2. —endnote]Iftheparameter-declaration-clauseisempty,thefunctiontakesnoarguments.Theparameter list (void) is equivalent to the empty parameter list. Except for this special case, void shall not be a parameter type (though types derived from void, such as void*, can). If the parameter-declaration-clause terminates with an ellipsis, the number of arguments shall be equal to or greater than the number of parameters that do not have a default argument. Where syntactically correct, “, ...” is synonymous with “...”.
The grammar for a parameter-declaration-clause allows it to end in either ... or , .... I found this question and the answers said that initially the grammar allowed only ..., and the comma variant (, ...) was introduced for compatibility with C.
My question is why does the quoted paragraph say "where syntactically correct"? Considering that function parameter packs or pack expansions were not present in C++03, are there any cases where it would be "syntactically incorrect" to consider ... synonymous with , ...?
Thank you.
for my understanding, it just mean that when you use ,... with a correct syntax, then it can be replaced by ...
for instance :
int printf(const char*, ...); is a correct syntax and can be replaced by int printf(const char*...);
int printf(,...); is not syntactically correct and is not equivalent to int printf(...);
You can easily try in a C code by just adding the following prototypes:
void printf(...); --> works
void printf(,...); --> expected primary-expression before ‘,’ token
are there any cases where it would be "syntactically incorrect" to consider ... synonymous with , ...?
Exactly as Guillaume says, it would be "syntactically incorrect" to rewrite
foo(...)
as
foo(, ...)
so that clause just handles the corner case where there is no prior parameter from which the ellipsis can be separated by a comma.
template<typename... T>
void foo(T... args);
In the above example, T is expanded according to §14.5.3 - (4.1) of the standard.
§14.5.3 - (4.1) — In a function parameter pack (8.3.5); the pattern is the parameter-declaration without the ellipsis.
What exactly is happening here? Let's say I call the function with 3 integers.
foo(1, 2, 3);
Is the parameter pack being expanded like
foo(int arg1, int arg2, int arg3);
where arg1, arg2, and arg3 are just arbitrary names given to by the compiler?
The standard says how "the pattern is the parameter-declaration without the ellipsis"
The other way I interpret that is args gets a single parameter-declartion.Is args getting its own type? I've tried doing
std::cout << typeid(args).name;
but that doesn't work, and throws compiler errors. So I could assume it's not getting its own type. Could someone "dumb down" what really is happening here, and the behavior of the function parameter pack?
Alright, I think I've figured it out. Correct me if I'm wrong.
A parameter expansion happens when the ellipsis is on the right on the pattern. Our pattern here is simply just T:
foo(T... args);
The standard states that the result of this will be a parameter-declaration. This decays into:
attribute-specifier-seqopt decl-specifier-seq declarator
attribute-specifier-seq can be ignored.
decl-specifier-seq is the type, T;
declarator is ... args
Semantically, this is a function parameter pack declaration. Nothing special.
Once again, my curiosity causes me to go insane for a little... heh.
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.
When compiling in C++ I often end up with error messages dealing with "formal parameters", such as
error C2719: 'b': formal parameter with __declspec(align('16')) won't be aligned
I do understand the error, and the fact that b is a parameter of a function I am defining.
However, what does it mean that a parameter is formal? Can there be informal parameters as well?
I do notice that the term "formal parameter" appears in other languages as well, so I presume it is a more generic term not necessarily specific to C-family of languages? Are informal parameters supported by some subset of languages?
Upon seeing the answers, one final question: Where those names formal parameter and actual parameter origin from? Does it origin from the C standard, or is it an effect of calling it as such in some abstract language calculus?
There are formal and actual parameters:
void foo(int arg); //arg is a formal parameter
int main()
{
int val = 1;
foo(val); //val is an actual parameter
}
From C++ Standard:
1.3.1 formal parameter (parameter)
an object or reference declared as part of a function declaration or
definition, or in the catch clause of an exception handler, that
acquires a value on entry to the function or handler; an identifier
from the comma-separated list bounded by the parentheses immediately
following the macro name in a function-like macro definition; or a
template-parameter. Parameters are also known as formal arguments or
formal parameters.
1.3.10 actual parameter (argument)
an expression in the comma-separated list bounded by the parentheses
in a function call expression, a sequence of preprocessing tokens in
the comma-separated list bounded by the parentheses in a function-like
macro invocation, the operand of throw, or an expression, type-id or
template-name in the comma-separated list bounded by the angle
brackets in a template instantiation. Also known as an actual argument
or actual parameter.
Formal parameters are the parameters known at the function definition. The actual parameters are what you actually (hence the name) pass to the function when you call it.
void foo( int a ); // a is a formal parameter
foo(10); // 10 is the actual parameter
It's a matter of being a little pedantic over terminology, but quite useful: The formal parameters are what you just think of function parameters:
int foo(bool a, float b);
Here a and b are formal parameters. The point is that in the function body, you're referring to those parameters "formally" without actually knowing their value. It is only when you actual evaluate a function call expression that the formal function parameters are bound to the function call arguments:
int result = foo(false, 1.5);
In this call expression, the value false of the first argument is bound to the formal parameter a, and similarly for the second argument.
The distinction between parameters and arguments is maybe more important to language designers and comiler writers, but as an example in C++, it can be very helpful to get your head around this when you're trying to follow the rules for template argument deduction.