There are two standard signatures for main
as of the latest C language standard:
int main( void ) // void indicates "takes no arguments"
and
int main( int argc, char *argv[] ) // or char **argv, it means the same thing in this context
The names argc
and argv
are arbitrary; you can use different names if you wish.
Implementations may provide additional valid signatures for main
- check your compiler documentation.
If your program does not take any command line arguments, use the first form, otherwise use the second.
C function declaration and definition syntax has evolved a bit over time, which is why different references use different conventions.
Implicit Typing
First of all, C originally allowed for implicit int
declarations - if the compiler saw a function definition or declaration without a type specifier, it assumed the function returned int
:
foo(); // modern equivalent: int foo( void )
This was allowed up until the 1999 standard, although was considered bad style by most of us long before then.
The void
keyword was not introduced until the 1989 standard. As a type specifier, it indicates a type with no values. As an identifier in a function parameter list, it indicates that the function takes no arguments.
Before the introduction of the void
keyword, there was no good way (other than documentation) to distinguish between functions that returned a value you were meant to use vs. functions that just executed some action. Some of us used the "implicit int
" convention to indicate those functions weren't meant to return anything meaningful:
foo(); /* returns int, but return value not meant to be used */
int bar(); /* returns int, return value meant to be used */
Again, this was just a convention, and far from universal. Now we'd use the void
keyword:
void foo(); /* does not return a value */
int bar(); /* returns int */
Function Prototype Syntax
Originally, a function definition looked something like this:
foo( bar, bletch, blurga )
int bar;
double bletch;
char *blurga;
{
/* function body */
}
The parameter list only specified the names of the parameters, not their types; that was done in a separate set of declarations between the function declarator and the opening {
of the function body. A function that took no arguments had an empty identifier list in the function definition:
blah( )
{
/* function body */
}
Function declarations only specified the name and return type of the function; it didn't specify the parameters at all:
foo( ); /* no bar, bletch, or blurga */
An empty identifier list in a function declaration indicates that the function takes an unspecified number of arguments, not zero arguments. The compiler could check that the return type of the function call was being used correctly, but it could not check that the number and types of parameters in the call were correct.
The 1989 language standard introduced the concept of function prototype syntax, where the type of each parameter was specified along with its name in the parameter list:
foo( int bar, double bletch, char *blurga )
{
/* function body */
}
This applied to both the function declaration and definition:
foo( int bar, double bletch, char *blurga );
This change allowed the compiler to check that the number and types of parameters in a function call were correct, along with the return type. In addition, the void
keyword could be used in the parameter list to indicate that the function took no parameters, in both the definition and declaration:
blah( void ); /* declaration, returns int, takes no parameters */
blah( void ) /* definition */
{
/* function body */
}
So yeah, depending on which language revision you're working against, main
would be written differently:
K&R:
main() main( argc, argv )
{ int argc;
... char *argv[];
} {
...
}
C89:
main( void ) main( int argc, char *argv[] )
{ {
... ...
} }
C99 and later:
int main( void ) int main( int argc, char *argv[] )
{ {
... ...
} }