我试图理解如何用替换WinMain
的不同入口点在Microsoft工具链中工作。
我已经找到了this question并且它非常有用,但最后一个细节是在唠叨我。
我第一次在Visual Studio中更改了Linker>Advanced>Entry Point
选项,我错误地将它设置为main
并且我的程序编译并运行正常。我后来意识到并重建了程序,设置为mainCRTStartup
,因为链接问题中的接受答案表明,并没有发现任何不同。
所以,我的问题是:main
和mainCRTStartup
之间是否存在任何差异?若然,有什么区别?
main()是C或C ++程序的入口点。 mainCRTStartup()是C运行时库的入口点。它初始化CRT,调用您在代码中编写的任何静态初始化器,然后调用main()函数。
显然,首先执行CRT和您自己的初始化是至关重要的。如果没有发生,你可能会很难诊断出错误。也许你不会,这是一个废话。您可以通过在小型C ++程序中粘贴此代码来测试的内容:
class Foo {
public:
Foo() {
std::cout << "init done" << std::endl;
}
} TestInit;
如果将入口点更改为“main”,那么您将看到构造函数永远不会被调用。
这是不好的。
在VS2017中,创建一个控制台C ++应用程序:
#include "pch.h"
#include <iostream>
int func()
{
return 1;
}
int v = func();
int main()
{
}
在main()中设置断点并开始调试,然后调用堆栈如下:
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
所以程序入口点是mainCRTStartup,最后调用C入口点main(),v的值为1。
现在将Linker> Advanced> Entry Point设置为“main”并开始调试,现在调用堆栈是:
> testCppConsole.exe!main() Line 8 C++
kernel32.dll!@BaseThreadInitThunk@12() Unknown
ntdll.dll!__RtlUserThreadStart() Unknown
ntdll.dll!__RtlUserThreadStart@8() Unknown
因此main()成为程序入口点,并且此时v的值将为0,因为根本不调用CRT init函数,因此不会调用func()。
现在将代码修改为:
#include "pch.h"
#include <iostream>
extern "C" int mainCRTStartup();
extern "C" int entry()
{
return mainCRTStartup();
}
int func()
{
return 1;
}
int v = func();
int main()
{
}
并将链接器>高级>入口点设置为“条目”并开始调试,现在调用堆栈是:
> 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
程序入口点是entry(),它调用mainCRTStartup()调用CRT init函数,调用func()到init v,mainCRTStartup()最后调用main()。