Reputation: 395
I know that “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„[1]:
// No information about the parameters is supplied.
int foo();
I know that “an empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters„[2].
// In this case the foo() function has no parameters.
int foo()
{
// ...
}
I know that “the special case of an unnamed parameter of type void
as the only item in the list specifies that the function has no parameters„[3]:
// foo() has no parameters.
int foo(void);
// bar() has no parameters.
int bar(void)
{
// ...
};
So here are some questions:
Is int main() { /* ... */ }
legal? The standard states[4] that
The function called at program startup is named
main
. The implementation declares no prototype for this function. It shall be defined with a return type ofint
and with no parameters:int main(void) { /* ... */ }
or with two parameters (referred to here as
argc
andargv
, though any names may be used, as they are local to the function in which they are declared):int main(int argc, char *argv[]) { /* ... */ }
or equivalent; or in some other implementation-defined manner.
So, is int main() { /* ... */ }
is equivalent to int main(void) { /*... */ }
?
Why GCC allows pass parameters to a function that has no parameters?
int foo();
int bar()
{
return 42;
}
int main(void)
{
// Should be OK.
foo(13);
// Should give a compile-time error.
bar(1, 12);
}
But I actually can compile the program with gcc version 10.1.0 (GCC)
: gcc -std=c17 -Werror -c test.c
.
I've read some related questions, such as What are the valid signatures for C's main() function?, but they do not take into account the following standard clause[2]:
An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.
So, is my understanding of this clause correct?
Upvotes: 5
Views: 1247
Reputation: 140748
Per the letter of the standard, yes. 5.1.2.2.1 says "[main] shall be defined with a return type of int[,] and with no parameters, or with two parameters [...]". int main() {}
is a definition with return type int
and no parameters, and 5.1.2.2.1 does not say anywhere that the definition is required to be prototyped.
(The code fragment shown immediately after "and with no parameters" may appear to be making a requirement to write (void)
, but all code fragments are considered to be examples, and therefore non-normative. It doesn't actually say this anywhere in the text, but it has come up in DR responses at least a couple times; I regret I do not remember specific numbers, it was more than 15 years ago now.)
However, because of (2), you should write int main(void)
anyway.
Section 6.5.2.2 (semantics of function calls), paragraph 8, says "the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator." However, paragraph 6 of the same section says that in the event of an actual mismatch between the definition and the callsite the behavior is undefined. That means, compilers are allowed to issue an error when a function defined as T foo() {}
is called with arguments, but it also means they are allowed not to issue an error.
For the sake of backward compatibility with pre-C89 code, which regularly did make function calls with a mismatched number of arguments, many compilers will accept such code without complaint. I have seen this behavior with Clang and MSVC as well as GCC. Newer versions of Clang do give you a warning:
$ clang --version | head -1
clang version 9.0.1-13
$ clang test.c
test.c:14:14: warning: too many arguments in call to 'bar'
bar(1, 12);
~~~ ^
I don't know how long this warning's been on by default.
Someone ought to go through all of GCC's intentional leniences for the sake of backward compatibility with really old code, and turn many of them off by default, but nobody's interested in funding this so it probably won't ever happen.
Upvotes: 3
Reputation: 120021
This standard is vague on this. It does not really define what "or equivalent" means. However you may want to know that the standard uses int main()
in at least one code example. Code examples are not normative though.
The call site doesn't see a definition. It only sees a declaration. The (draft document N2176) standard says
[6.9.1/7] If the declarator includes a parameter type list, the list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit.
A declarator without a parameter type list does not serve as a function prototype for later calls, even if it is a part of a definition.
[6.5.2.2/8] the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator.
Upvotes: 3