Just wondering why this
int main(void){}
compiles and links
and so does this:
int main(int argc, char **argv){}
Making it work has to do with the binary format of the executable and the OS's loader. The linker doesn't care (well it cares a little: it needs to mark the entry point) and the only caller routine is the loader.
The loader for any system must know how to bring supported binary format into memory and branch into the entry point. This varies slightly by system and binary format.
If you have a question about a particular OS/binary format, you may want to clarify.
Because the calling code can, for example, pass arguments in registers or on the stack. The two argument main uses them, while the zero argument main does nothing with them. It's that simple. Linking does not even enter the picture.
If you are worried about stack adjustments in the called code, the main
function just needs to make sure the stack pointer is the same when it returns (and often even this is of no importance, e.g. when the ABI states that the caller is responsible for stack management).
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
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.
The first counts the arguments supplied to the program and the second is an array of pointers to the strings which are those arguments. These arguments are passed to the program by the command line interpreter. So, the two possibilities are handled as:
If no parameters are declared: no parameters are expected as input.
If there are parameters in
main()
,they should:
argc
is greater than zero.argv[argc]
is a null pointer.argv[0]
through toargv[argc-1]
are pointers to strings whose meaning will be determined by the program.argv[0]
will be a string containing the program's name or a null string if that is not available. Remaining elements ofargv
represent the arguments supplied to the program. In cases where there is only support for single-case characters, the contents of these strings will be supplied to the program in lower-case.
they will be placed on the stack just above the return address and the saved base pointer (just as any other stack frame).
they will be passed in registers, depending on the implementation.
I am taking a Linux point of view below.
The main
function is very special in the standard definition (for hosted C11 implementations). It is also explicitly known by recent compilers (both GCC & Clang/LLVM....) which have specific code to handle main
(and to give you this warning). BTW, GCC (with help from GNU libc headers thru function attributes) has also special code for printf
. And you could add your own customization to GCC using MELT for your own function attributes.
For the linker, main
is often a usual symbol, but it is called from crt0 (compile your code using gcc -v
to understand what that really means). BTW, the ld(1) linker (and ELF files, e.g. executables or object files) has no notion of types or function signatures and deals only with names (This is why C++ compilers do some name mangling).
And the ABI and the calling conventions are so defined that passing unused arguments to a function (like main
or even open(2)...) does not do any harm (several arguments get passed in registers). Read the x86-64 System V ABI for details.
See also the references in this answer.
At last, you really should practically define your main
as int main(int argc, char**argv)
and nothing else, and you hopefully should handle program arguments thru them (at least --help
& --version
as mandated by GNU coding standards). On Linux, I hate programs (and I curse their programmers) not doing that (so please handle --help
& --version
).
The short answer: if you don't use the parameters, then you can declare main without parameters, in two ways:
int main(void)
or
int main()
The first means main
is a function with no parameters. The second means main
is a function with any number of parameters.
Since you don't access the parameters, both will be fine. Any compiler having "special" code to check the parameters of main
is wrong. (But: main
must return a value.)