Click here to Skip to main content
15,867,141 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
Hi,

We can write main function in several ways (sure there can be only one main in the program),
1. int main()
2. int main(int argc,char *argv[])
3. int main(int argc,char *argv[],char * environment)

How run-time CRT function knows which main should be called. Please notice here, I am not asking about Unicode supported or not.
Posted
Updated 29-Apr-12 3:12am
v2
Comments
Sergey Alexandrovich Kryukov 29-Apr-12 9:04am    
Do you know a way to write more then one?
--SA
[no name] 29-Apr-12 9:07am    
No, there can be only one main in program.
Sergey Alexandrovich Kryukov 29-Apr-12 9:08am    
Come to think about it, this question is not clear.

Do you mean:
1) Executable module may have more then one functions with the main name and signature. Which one will be called and how this is determined?

2) There is only one main with appropriate signature, one of them. How runtime determines which parameters to pass, as the signature is not known.

--SA
[no name] 29-Apr-12 9:12am    
Question edited
Sergey Alexandrovich Kryukov 29-Apr-12 9:31am    
Thank you. In fact, the question is pretty deep, so I voted 5 for it, and the answer is not very simple -- I tried to explain it, please see.
--SA

I don't know how specific compilers do it but GCC and VC++ come with the source code to their startup routines if you want a look.

The trick I used a while ago is for the startup code to not worry how main's been written. It just bungs two words (for a standard compiler) on the stack and jumps to calls the symbol called main. The two words are the same regardless of which of the functions have been written by the programmer. This doesn't require a lot of collusion with the compiler as most C compilers rely on the calling function to clean up the stack after them while other languages rely on the exit code function of the called function to do.

Cheers,

Ash

Just for SA:

The assembly language sequence for calling main on most compilers is this (assuming x86 and a compiler that doesn't add vendor specific parameters to the end of main):
push argp
push argc
call main
add  esp, 8

main returns just using a ret instruction.

As I said above, bung two words on the stack, call main (like I didn't edit what I said earlier from jump to main, ahem) and then rely on the calling function to clean up the stack.

While I'm on the subject there's nothing in the C standard that says a compiler couldn't either stick the words the other way around, AND/OR rely on main to clean up the stack. So there's no reason why a compiler couldn't use a Pascal or Fortran style calling convention (MS __stdcall parameters without the name decoration, the @8 or @12 on some compilers):
push argc
push argp
call main

and rely on main to do a ret 8.
 
Share this answer
 
v4
Comments
[no name] 29-Apr-12 9:15am    
Thanks. 5!
Sergey Alexandrovich Kryukov 29-Apr-12 9:32am    
I don't think this is the answer. Please see mine -- it explain the essence of it. This is specific to C, C++ and the parameter passing convention.
--SA
Thank you for clarification of the question on my request.

Yes, if you try to create more then one, the development environment should give you an error like "overloading of main is not allowed" or something.

So, how the run-time system knows what signature to use while calling the method? In general case, no reflection is possible (like in .NET), so how to determine what parameters to pass?

Short answer is: it is possible due to __cdecl, by passing maximum number of parameters in all cases and always using return value.

First, pay attention that all signatures are compatible: more "advanced" signature only adds additional parameters:

C++
int main(void)
int main(int argc, char **argv)
int main(int argc, char *argv[]) //same as before
int main(int argc, char **argv, char **envp)


(http://en.wikipedia.org/wiki/Main_function#C_and_C.2B.2B[^])

The trick is here: the argument passing conventions. It is always __cdecl. This is the only convention when the stack cleanup is done by the caller, not the callee:
http://msdn.microsoft.com/en-us/library/984x0h58%28v=vs.71%29.aspx[^].

In this case, the caller can pass all the parameters as in the case of the longest signature and always returns int value. As the return value is returned in the CPU register, it does not disrupt the operation on the called function does not use it: it is simply ignored. All the parameters are available on the stack, so the called function only uses as many as its signature allows; all other are just ignored. As the stack is cleaned up by the caller (run-time system), it does not need to know what was the actual signature of the callee — all parameters are passed, and, respectively, all are removed by the caller.

Try to specify the calling conventions explicitly:
C++
int __cdecl main(int argc, char **argv)

It will compile and link. Try to use __stdcall or any other — the linker will fail. You can only use __cdecl. This is designed so by the reasons I explained above.

—SA
 
Share this answer
 
v2
Comments
[no name] 29-Apr-12 9:35am    
Thanks SA for such comprehensive answer(as expected). 5!
Sergey Alexandrovich Kryukov 29-Apr-12 16:47pm    
You are very welcome, Pranit.
--SA
[no name] 29-Apr-12 10:13am    
I like this explanation.
Sergey Alexandrovich Kryukov 29-Apr-12 16:47pm    
Thank you.
--SA
Espen Harlinn 29-Apr-12 17:18pm    
Good answer Sergey :-D
The question is indeed a good one. If the main function was compiled as a regular C++ function, its name would be mangled and the runtime system had no way to know, which of the various signatures were provided by the user.

Here is how VC++ does it: When looking at the linker map you see that the main function is listed as "_main", thus as a good old C function, without name mangling. That is how the runtime finds it. It just looks for a function called "main".

As for the parameters that are being passed, SA and Ash have already explained that part in depth. The runtime just pushes them on the stack or transfers them in registers and cleans up afterwards. If main just ignores them - fine.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900