Posts Tagged ‘code entrypoint’

void main() v/s int main()

January 8th, 2009 2 comments

Many people use void main() instead of int main() while writing C/C++ programs, inspite of void not being accepted as a return type for main in the C/C++ standard.

I too used to do the same until some programmers on a programming forum told me a few years ago about the C++ Standard.

But what does void do anyway? How is it different from return 0?

I disassembled a few test programs to check what really happens under the hood.  It is interesting to know what happens when a program is executed.

Almost everybody believes that main()/WinMain() is the entrypoint of all C/C++ programs but it isn’t so.

On Windows, a start() function gets called before the main() function. It first calls GetVersion(), GetCommandLine(), GetEnvironmentStrings(), GetStartupInfo() and GetModuleHandle() API Functions from kernel32.dll in the exact order. Then it passes the Module Handle, command-line arguments and environment variables as arguments to main() and then calls it.

But what about main()’s return value? Is it read after main() quits?

It doesn’t matter what data type you return from main(). Whether its int or void it doesn’t make any difference.
Here’s what actually happens.
In an executable file, the start() function which calls the main() function, expects a return value of data type integer so that it may decide what argument is passed to the exit() function which is called after main().
If void is chosen as the return type for main, the EAX register is passed as an argument to the exit function.
Since the EAX register almost always contains the return value of any function, so if we say return 0, EAX would be set to zero, that’s all.
Generally whenever void is used, EAX is set to zero at the end of main() , so it is exactly the same as passing return 0.
But since void main() is not a part of the standard, compiler developers are given full freedom to design their own implementation of the code after main() returns. Hence, we cannot always assume that EAX is set to 0 with a void main().

Ever wondered what happens to the return value after main() quits?
Take a look at this disassembled snippet of the start() function from a C/C++ program.

call dword ptr [esi+18h] ; call main()
add esp, 0Ch
; (4 x 3) 12 bytes are cleared from the stack to clear space
; occupied by main()'s three arguments.
push eax ; status for exit. Return value of main() is pushed
call _exit

So no matter what you do, even if you ignore the return value type, the compiler will still pass the contents of the EAX Register into the exit function. This could lead to some unwanted results, and hence it is better to return 0 (ie. EXIT_SUCCESS) or 1(EXIT_FAILURE) depending on when and why you have designed the program to end.

So even though, it is almost always the same, there is a reason why the standard recommends using int. Simply for the following reasons:
returning 0 by default is COMPILER DEPENDENT.
No Guarantee about the content of the EAX Register after main() exits.
Will not be portable to all Operating Systems.
May cause incorrect termination of main()

So even though void main and return 0 are alike, we should try to avoid its use.