There are some notes to do.
The standard basically says what most likely main is: a function taking no arguments, or a function taking two arguments, or whatever else!
See for example my answer to this question.
But your question points to other facts.
Why does this work? Answer: Because
the standard says so!
It is not correct. It works for other reasons. It works because of the calling conventions.
These convention can be: arguments are pushed on stack, and the caller is responsible for cleaning the stack. Because of this, in actual asm code, the callee can totally ignore what is on the stack. A call looks like
push value1
push value2
call function
add esp, 8
(intel examples, just to stay in the mainstream).
What function does with the arguments pushed on stack, is totally uninteresting, everything will still work fine! And this is indeed true even if the calling convention are different, e.g.
li $a0, value
li $a1, value
jal function
If function takes into account the registers $a0 and $a1 or not, does not change anything.
So callee can ignore without harms arguments, cn believe they do not exist, or it can know they exist, but prefer to ignore them (on the contrary, it would be problematic if the callee gets values from the stack or registers, while the caller passed nothing).
This is why things work.
From the C point of view, if we are on a system where the startup code calls the main with two arguments (int and char **) and expect an int return value, the "right" prototype would be
int main(int argc, char **argv) { }
But let us suppose now that we do not use these arguments.
It is more correct to say int main(void)
or int main()
(still in the same system where the implementation calls the main with two args and expect an int return value, as said before)?
Indeed standard does not say what we have to do. The correct "prototype" that says that we have two arguments is still the one shown before.
But from a logical point of view, the right way of saying that there are arguments (we know it) but we are not interested in them, is
int main() { /* ... */ }
In this answer I've shown what it happens if we pass arguments to a function declared as int func()
and what happens if we pass arguments to a function declared as int func(void)
.
In the second case we have an error since (void)
explicitly says the function has no arguments.
With main
we can't get an error since we have no a real prototype mandating for arguments, but it is worth noting that gcc -std=c99 -pedantic
gives no warning for int main()
nor for int main(void)
, and this would mean that 1) gcc is not C99 compliant even with the std
flag, or 2) both ways are standard compliant. More likely it is the option 2.
One is explicitly standard compliant (int main(void)
), the other is indeed int main(int argc, char **argv)
, but without explicitly saying the arguments, since we are not interested in them.
int main(void)
works even when arguments exist, because of what I've written before. But it states that main takes no argument. While in many cases, if we can write int main(int argc, char **argv)
, then it is false, and int main()
must be preferred instead.
Another interesting thing to notice is that if we say main does not return a value (void main()
) on a system where the implementation expects a return value, we obtain a warning. This is because the caller expect it to do something with it, so that it is "undefined behaviour" if we do not return a value (which it does not mean putting an explicit return
in the main
case, but declaring main
as returning an int).
In many startup codes I've seen the main is called in one of these ways:
retval = main(_argc, _argv);
retval = main(_argc, _argv, environ);
retval = main(_argc, _argv, environ, apple); // apple specific stuff
But there can exist startup codes that calls main differently, e.g. retval = main()
; in this case, to show this, we can use int main(void)
, and on the other hand, using int main(int argc, char **argv)
would compile, but make the program crash if we actually use the arguments (since the retrieved values will be rubbish).
Is this platform dependant?
The way the main is called is platform dependent (implementation specific), as allowed by standards. The "supposed" main prototype is a conseguence and as already said, if we know there are arguments passed in but we shall not use them, we should use int main()
, as a short-form for longer int main(int argc, char **argv)
, while int main(void)
means something different: i.e. main takes no arguments (that is false in the system we are thinking about)