Consider the very simple:
int main(void) { return 0; }
I compiled it (with mingw32-gcc) and executed it as main.exe foo bar
.
Now, I had expected some sort of crash or error caused by a main function explicitly declared as being bereft of life parameters. The lack of errors led to this question, which is really four questions.
Why does this work? Answer: Because the standard says so!
Are the input parameters just ignored or is the stack prepared with argc & argv silently? Answer: In this particular case, the stack is prepared.
How do I verify the above? Answer: See rascher's answer.
Is this platform dependant? Answer: Yes, and no.
Per the letter of the standard, yes Even though both T f() { ... } and T f(void) { ... } define a function with no parameters, these definitions are not 100% equivalent: the first form doesn't provide function prototype.
Here, argc (argument count) stores the number of the arguments passed to the main function and argv (argument vector) stores the array of the one-dimensional array of strings. So, the passed arguments will get stored in the array argv and the number of arguments will get stored in the argc .
The first parameter, argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started. The second parameter, argv (argument vector), is an array of pointers to arrays of character objects.
Yes, we can give arguments in the main() function.
I don't know the cross-platform answer to your question. But this made me curious. So what do we do? Look at the stack!
For the first iteration:
test.c
int main(void) { return 0; }
test2.c
int main(int argc, char *argv[]) { return 0; }
And now look at the assembly output:
$ gcc -S -o test.s test.c $ cat test.s .file "test.c" .text .globl main .type main, @function main: pushl %ebp movl %esp, %ebp movl $0, %eax popl %ebp ret .size main, .-main .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3" .section .note.GNU-stack,"",@progbits
Nothing exciting here. Except for one thing: both C programs have the same assembly output!
This basically makes sense; we never really have to push/pop anything off of the stack for main(), since it's the first thing on the call stack.
So then I wrote this program:
int main(int argc, char *argv[]) { return argc; }
And its asm:
main: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax popl %ebp ret
This tells us that "argc" is located at 8(%ebp)
So now for two more C programs:
int main(int argc, char *argv[]) { __asm__("movl 8(%ebp), %eax\n\t" "popl %ebp\n\t" "ret"); /*return argc;*/ } int main(void) { __asm__("movl 8(%ebp), %eax\n\t" "popl %ebp\n\t" "ret"); /*return argc;*/ }
We've stolen the "return argc" code from above and pasted it into the asm of these two programs. When we compile and run these, and then invoke echo $?
(which echos the return value of the previous process) we get the "right" answer. So when I run "./test a b c d" then $?
gives me "5" for both programs - even though only one has argc/argv defined. This tells me that, on my platform, argc is for sure placed on the stack. I'd bet that a similar test would confirm this for argv.
Try this on Windows!
From the C99 standard:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With