What is the difference between main and mainCRTStartup?

In VS2017,create a console C++ application:

#include "pch.h"
#include <iostream>
int func()
{
    return 1;
}
int v = func();

int main()
{

}

set a breakpoint in main() and begin debug,then the call stack is like:

testCppConsole.exe!main() Line 8    C++
testCppConsole.exe!invoke_main() Line 78    C++
testCppConsole.exe!__scrt_common_main_seh() Line 288    C++
testCppConsole.exe!__scrt_common_main() Line 331    C++
testCppConsole.exe!mainCRTStartup() Line 17 C++
kernel32.dll!@BaseThreadInitThunk@12()  Unknown
ntdll.dll!__RtlUserThreadStart()    Unknown
ntdll.dll!__RtlUserThreadStart@8()  Unknown

So the program entry point is mainCRTStartup,it finally calls the C entry point main(),and the value of v will be 1.

Now set Linker>Advanced>Entry Point to "main" and begin debug,now the call stack is:

>   testCppConsole.exe!main() Line 8    C++
    kernel32.dll!@BaseThreadInitThunk@12()  Unknown
    ntdll.dll!__RtlUserThreadStart()    Unknown
    ntdll.dll!__RtlUserThreadStart@8()  Unknown

So main() become the program entry point,and for this time the value of v will be 0,because CRT init functions are not called at all,so func() won't be called.

Now modify the code to :

#include "pch.h"
#include <iostream>

extern "C" int mainCRTStartup();
extern "C" int entry()
{
    return mainCRTStartup();
}

int func()
{
    return 1;
}
int v = func();

int main()
{

}

and set Linker>Advanced>Entry Point to "entry" and begin debug,now the call stack is:

>   testCppConsole.exe!main() Line 14   C++
    testCppConsole.exe!invoke_main() Line 78    C++
    testCppConsole.exe!__scrt_common_main_seh() Line 288    C++
    testCppConsole.exe!__scrt_common_main() Line 331    C++
    testCppConsole.exe!mainCRTStartup() Line 17 C++
    testCppConsole.exe!entry() Line 10  C++
    kernel32.dll!@BaseThreadInitThunk@12()  Unknown
    ntdll.dll!__RtlUserThreadStart()    Unknown
    ntdll.dll!__RtlUserThreadStart@8()  Unknown

and v will be 1 again.Program entry point is entry(),it calls mainCRTStartup() which call CRT init funtions which calls func() to init v,and mainCRTStartup() finally calls main().


main() is the entrypoint of your C or C++ program. mainCRTStartup() is the entrypoint of the C runtime library. It initializes the CRT, calls any static initializers that you wrote in your code, then calls your main() function.

Clearly it is essential that both the CRT and your own initialization is performed first. You can suffer from pretty hard to diagnose bugs if that doesn't happen. Maybe you won't, it is a crap-shoot. Something you can test by pasting this code in a small C++ program:

class Foo {
public:
    Foo() {
        std::cout << "init done" << std::endl;
    }
} TestInit;

If you change the entrypoint to "main" then you'll see that the constructor never gets called.

This is bad.

Tags:

Winapi