你真的需要C++中的main()吗?

one*_*sse 27 c++

从我可以告诉你,当创建一个全局对象,你可以揭开序幕在构造函数中的所有动作.所以,你真的需要C++中的main()函数,或只是遗产?

我可以理解这样做可能被认为是不好的做法.我只是出于好奇而问.

Joh*_*itb 30

如果要在托管C++实现上运行程序,则需要一个main函数.这就是事情的定义方式.如果你想要的话,你可以把它留空.在技​​术方面,链接器想要解析main运行时库中使用的符号(它没有任何关于你的特殊意图的线索来省略它 - 它仍然只是调用它).如果标准指定main是可选的,那么当然实现可以提出解决方案,但这需要在并行Universe中进行.

如果你使用"我的全局对象的构造函数中的执行开始",请注意你自己设置了许多与不同翻译单元中定义的命名空间作用域对象的构造顺序相关的问题(那么什么入口点?答案是:您将有多个入口点,并且首先执行的入口点是未指定的!).在C++ 03中,你甚至不能保证它cout是正确构造的(在C++ 0x中你可以保证它是在任何代码尝试使用它之前,只要有一个前面的包含<iostream>).

你没有那些问题,如果你正确地开始执行它们,就不需要解决它们(这可能非常棘手)::main.


正如在评论中提到的,不过是掩盖一些系统main通过使他告诉这是中实例化的类的名字从用户main.这与以下示例类似

class MyApp {
public:
  MyApp(std::vector<std::string> const& argv);

  int run() {
      /* code comes here */
      return 0;
  };
};

IMPLEMENT_APP(MyApp);
Run Code Online (Sandbox Code Playgroud)

对于这个系统的用户来说,完全隐藏有一个main函数,但是这个宏实际上会定义如下的主函数

#define IMPLEMENT_APP(AppClass) \
  int main(int argc, char **argv) { \
    AppClass m(std::vector<std::string>(argv, argv + argc)); \
    return m.run(); \
  }
Run Code Online (Sandbox Code Playgroud)

这不具有上述结构的未指定顺序的问题.它们的好处是它们可以使用不同形式的更高级别的入口点.例如,Windows GUI程序在一个WinMain函数中启动- IMPLEMENT_APP然后可以在该平台上定义这样的函数.


Ter*_*ver 5

是的!你可以去掉 main.

免责声明:您问的是是否可能,而不是是否应该这样做。这是一个完全不受支持的坏主意。我自己也这样做过,原因我不会详细说明,但我不推荐这样做。我的目的不是摆脱 main,但它也可以做到这一点。

基本步骤如下:

  1. crt0.c在编译器的 CRT 源目录中查找。
  2. 添加crt0.c到您的项目(副本,而不是原始项目)。
  3. 查找并删除对 main 的调用crt0.c

编译和链接它可能很困难;难度取决于哪个编译器和哪个编译器版本。

添加

我刚刚使用 Visual Studio 2008 完成了此操作,因此以下是让它与该编译器一起工作所需执行的具体步骤。

  1. 创建一个新的 C++ Win32 控制台应用程序(单击“下一步”并选中Empty Project)。
  2. 添加新项目..C++ 文件,但为其命名crt0.c(而不是 .cpp)。
  3. 复制 的内容C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src\crt0.c并粘贴到crt0.c.
  4. 找到mainret = _tmain(__argc, _targv, _tenviron);并注释掉它。
  5. 右键单击crt0.c并选择属性。
  6. 设置 C/C++ -> 常规 -> 附加包含目录 = "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src"
  7. 设置 C/C++ -> 预处理器 -> 预处理器定义 = _CRTBLD
  8. 单击“确定”。
  9. 右键单击项目名称并选择属性。
  10. 设置 C/C++ -> 代码生成 -> 运行时库 = Multi-threaded Debug (/MTd)(*)。
  11. 单击“确定”。
  12. 添加新项目..C++ 文件,将其命名为任意名称(app.cpp对于本例)。
  13. 将下面的代码粘贴到app.cpp并运行它。

(*) 您不能使用运行时 DLL,必须静态链接到运行时库。

#include <iostream>

class App
{
    public: App()
    {
        std::cout << "Hello, World! I have no main!" << std::endl;
    }
};

static App theApp;
Run Code Online (Sandbox Code Playgroud)

添加

我删除了多余的 exit 调用和关于生命周期的简介,因为我认为我们都有能力理解删除 main 的后果。

究极死灵

我刚刚看到这个答案并阅读了它和下面约翰·迪布林的反对意见。显然,我没有解释上述过程的作用以及为什么它确实从程序中完全删除了 main 。

约翰断言,CRT 中“总有一个主线”。这些话严格来说并不正确,但该声明的精神是正确的。Main不是CRT提供的函数,必须自己添加。对该函数的调用位于 CRT 提供的入口点函数中。

每个 C/C++ 程序的入口点都是名为“crt0”的模块中的一个函数。我不确定这是否是约定或语言规范的一部分,但我遇到的每个 C/C++ 编译器(很多)都使用它。这个函数主要做了三件事:

  1. 初始化 CRT
  2. 呼叫主
  3. 拆除

在上面的示例中,调用是 _tmain,但这是一些宏魔法,允许“main”可以具有各种形式,其中一些在本例中是 VS 特定的。

上述过程的作用是从 CRT 中删除模块“crt0”并用新模块替换。这就是为什么您不能使用运行时 DLL,该 DLL 中已经存在一个函数,其入口点名称与我们添加的函数 (2) 相同。当您静态链接时,CRT 是 .lib 文件的集合,并且链接器允许您完全覆盖 .lib 模块。在这种情况下,一个模块只有一个功能。

我们的新程序包含库存 CRT,减去其 CRT0 模块,但带有我们自己创建的 CRT0 模块。在那里我们删除了对 main 的调用。所以哪里都没有主线!

(2) 您可能认为可以通过重命名 crt0.c 文件中的入口点函数并更改链接器设置中的入口点来使用运行时 DLL。但是,编译器不知道入口点更改,并且 DLL 包含对您未提供的“主”函数的外部引用,因此它无法编译。