【问题标题】:What is the difference between main and mainCRTStartup?main 和 mainCRTStartup 有什么区别?
【发布时间】:2014-04-08 10:24:34
【问题描述】:

我试图了解在 Microsoft 工具链中用不同的入口点替换 WinMain 的工作原理。

我已经找到了this question,它非常有帮助,但最后一个细节让我烦恼不已。

我第一次在 Visual Studio 中更改Linker>Advanced>Entry Point 选项时,我错误地将其设置为main,我的程序编译并运行良好。我后来意识到了这一点,并将其设置为mainCRTStartup 重新构建了程序,正如链接问题中接受的答案所暗示的那样,并没有发现任何不同。

所以,我的问题是:mainmainCRTStartup 之间有什么区别,如果有,有什么区别?

【问题讨论】:

  • mainCRTStartup 基本上是这样的:init_tls(); init_crt(); run_global_constructors(); get_args(&argc, &argv); ret = main(argc, argv); run_global_destructors(); exit(ret);。所以,main 就在那里,某个地方。

标签: winapi


【解决方案1】:

main() 是 C 或 C++ 程序的入口点。 mainCRTStartup() 是 C 运行时库的入口点。它初始化 CRT,调用您在代码中编写的任何静态初始化程序,然后调用您的 main() 函数。

显然,首先执行 CRT 和您自己的初始化是必不可少的。如果不发生这种情况,您可能会遇到很难诊断的错误。也许你不会,这是一个废话。您可以通过将此代码粘贴到一个小型 C++ 程序中来进行测试:

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

如果您将入口点更改为“main”,那么您将看到构造函数永远不会被调用。

这很糟糕。

【讨论】:

    【解决方案2】:

    在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()
    {
    
    }
    

    并将 Linker>Advanced>Entry Point 设置为“entry”并开始调试,现在调用堆栈为:

    >   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
    

    v 将再次为 1。程序入口点是 entry(),它调用 mainCRTStartup(),该函数调用 CRT init 函数,该函数调用 func() 来初始化 v,mainCRTStartup() 最后调用 main()。

    【讨论】:

      猜你喜欢
      • 2011-01-27
      • 2021-07-29
      • 2019-07-11
      • 1970-01-01
      • 1970-01-01
      • 2013-11-04
      • 1970-01-01
      • 2016-07-24
      • 2011-05-10
      相关资源
      最近更新 更多