Given (simplified) code snippet:
void foo(int a, int b); // declaration with prototype
int main(void)
{
foo(1, 5); // type-checked call (i.e. because of previous prototype)
return 0;
}
void foo() // old-style definition (with empty argument list)
{
}
and command-line options (though, as I checked they are not important):
-x c -std=c11 -pedantic -Wall
gcc 7.2 fails to compile it with following error message:
error: number of arguments doesn't match prototype
while clang 4.0 translates it without any complaints.
Which implementation is correct according to C Standard? Is it valid that old-style definition "cancels" previous prototype?
(C11, 6.7p4 Constraints) "All declarations in the same scope that refer to the same object or function shall specify compatible types"
and
(C11, 6.7.6.3p14) "An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. [...]"
My opinion is constraint of 6.7p4 is violated and diagnostic has to be issued.
EDIT:
as pointed out by @hvd it is actually not correct. 6.7.6.3p14 does not mean void foo() {}
provides a prototype for foo
as per DR#317. In that sense, the 6.7p4 constraint is not violated and so clang is right not to complain.
Disclaimer: I am not a language-lawyer, but I play one on stackoverflow.
If the compiler does not issue a diagnostic, it would be non-conforming, and could be considered a bug if the compiler claims to be conforming.
C.2011§6.7.6.3¶14 (emphasis mine):
An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
Thus, the definition of foo
specifies no parameters, while the declaration of foo
earlier specified two parameters.
C.2011§6.7.6.3¶15:
For two function types to be compatible, both shall specify compatible return types.146) Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types.
146) If both function types are ‘‘old style’’, parameter types are not compared.
Thus, the two declarators of foo
are not compatible.
Dang! From @hvd's comment:
It's well-established that
void foo()
does not provide a prototype, even in a definition. There was a DR that answered this explicitly. The type offoo
in that definition isvoid foo()
, notvoid foo(void)
, andvoid foo()
andvoid foo(int, int)
are compatible types. This answer is incorrect.
The emphasized part of the text above from the standard is the loophole that allows for the disagreement in number of arguments, but compatible types. Although the function definition specifies a function that takes no arguments, since the parameter type list is actually missing, there is actually no incompatibility between the type of foo
in its function prototype and the type of foo
in the function definition.
Thus, clang 4.0 seems to have it right, since there is no constraint violation.
My original argument becomes invalid, so editing out that part of my original answer.
In comments you actually presented the following example:
void foo () {}
int main () { foo(1, 2); return 0; }
And asked why the compiler does not complain for this case. This is actually addressed here, but in a nutshell: C.2011 still accepts K&R C function definition syntax. So, while void foo() {}
is a definition that takes no arguments, the prototype that is used for argument validation is the same as void foo();
, because the empty argument list is parsed as K&R. The modern C syntax to force proper argument checking would be to use void foo(void) {}
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With