Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are int main() and int main(void) equivalent prototypes in C23?

C23 introduced new semantics in function declarators:

6.7.6.3 Function declarators

[...]

13   For a function declarator without a parameter type list: the effect is as if it were declared with a parameter type list consisting of the keyword void. A function declarator provides a prototype for the function.

This seems to imply that a function definition with an empty parameter list can be written equivalently with () or (void).

Yet this equivalence does not seem guaranteed for the main function:

5.1.2.2.1 Program startup

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 of int and with no parameters:

int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, 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.

This does not seem to guarantee that int main() { /* ... */ } is a valid definition for main, or does equivalent cover this variant?


It troubles me that the 2 examples in C17 that use the syntax int main() (in 6.5.3.4 and 6.7.6.3) have been changed to use int main(void) in the latest C23 draft.

like image 554
chqrlie Avatar asked Sep 12 '25 17:09

chqrlie


2 Answers

In C17 and earlier versions of the standard, int main() { … } does not provide a prototype for main() but is otherwise equivalent to int main(void) { … }.

In C23, int main() { … } does provide a prototype for main() and is fully equivalent, except for spelling, to int main(void) { … }.

The difference only matters if you call main() recursively — something that is allowed in C and disallowed in C++. With int main() in C17 or earlier, a recursive call like main(23, "elephants"); is allowed because there is no prototype specified for main() (assuming that the definition of main() is visible before the recursive call). With int main(void), that is not allowed because there is a prototype in scope that says "no arguments".

Note what is said in What should main() return in C and C++? That has extensive discussions, including that the C17 and earlier standards use both int main() and int main(void) in their (non-normative) examples. It also points out what Microsoft specifies for Windows systems and what Annex J "Common Extensions" mentions (both recognize int main(int argc, char **argv, char **envp)). Apple even has a fourth optional argument to main()int main(int argc, char **argv, char **envp, char **apple) that behaves like argv or envp. I need to update my answer for C23 sometime soon.

like image 136
Jonathan Leffler Avatar answered Sep 15 '25 07:09

Jonathan Leffler


All code fragments in the standard are considered to be examples, and, therefore, non-normative.

The normative requirement is what the text says: "[main] shall be defined with a return type of int and with no parameters[, or ...]". In C2023, int main() { ... } defines main with a return type of int and with no parameters, so it meets the requirement.

As pointed out in the comments on the question, C2011 had language that meant a definition int main() { ... } would have, under that standard, defined main with a return type of int and with no parameters, although a declaration int main(); would not have declared main with no parameters. I cannot conveniently check C1999 or earlier from this computer.

like image 38
zwol Avatar answered Sep 15 '25 06:09

zwol