【问题标题】:What happens before main in C++?在 C++ 中 main 之前会发生什么?
【发布时间】:2020-08-09 22:16:36
【问题描述】:

我知道在 C 中,在main() 中启动应用程序之前,必须有一些实体:

  1. 初始化全局变量
  2. 将堆栈指针设置为最低堆栈区域地址(假设堆栈向上增长)

问题 1- 做这些事情的那个实体是什么?谁写的?

问题 2- C++ 中还有其他内容吗? 我假设对象构造函数和初始化都是在应用过程中完成的,main()

【问题讨论】:

  • 当你运行一个程序时,动态链接器在main之前做了很多事情。操作系统内核也做了很多。
  • 执行“这个东西”的实体有时被称为“启动代码”。它进行设置,然后调用main(),从main() 捕获返回值,然后进行任何清理。它通常由提供编译器和标准库的供应商编写,但可能使用主机系统提供的代码。在 C++ 中,编译器负责发出代码,确保文件范围内的静态对象的构造函数在 main() 之前调用 - 可能还有其他静态变量 - 并且(理想情况下)它们的析构函数在 main() 之后调用(以相反的顺序建设)。
  • @harper:这是对 C 的一个 hack,在 C++ 中,该语言具有本机功能(具有构造函数的全局对象)
  • 很多全局变量实际上不需要实例化代码,因为它们实际上存储在可执行文件的数据部分中。至于堆栈指针,在 bss 部分中通常为 8 KiB 的内核中(静态分配,但未设置)。在普通应用程序中,它可能是在运行时分配的。如果要查看启动代码反汇编可执行文件并查找导出的函数,通常命名为start。那是真正的入口点,它最终调用main。它还在 Windows 中调用 crtStartup 或其他名称。

标签: c++


【解决方案1】:

问题 1- 做这些事情的那个实体是什么?谁写的?

C 编译器团队编写。

会发生什么是特定于操作系统的,但基本上它会处理命令行参数、打开/连接标准输入、标准输出、标准错误等。

如果您挖掘 gcc 或 clang 源代码,我相信您可以找到代码1。如果您的程序不需要它,您可以将选项传递给链接器以不包含此代码。例如,如果您不读取参数也不使用文件,并且您想自己进行任何其他设置,您可以传入不包含启动代码的参数。

问题 2- C++ 中还有其他内容吗?

是的,C 中没有构造函数和析构函数这样的东西,所以如果没有其他东西,C++ 就必须处理这些。

1:here's an example

【讨论】:

    【解决方案2】:

    很大程度上取决于执行环境。在 C 运行时启动之前,操作系统加载程序可能会完成大量工作,这是可执行文件运行的一部分。设置执行环境的这个依赖于操作系统的部分对于所有本机(机器语言)可执行文件都是通用的,无论源实现语言如何。

    操作系统扮演的角色以及可执行文件中的代码执行的内容因执行环境而异。操作系统加载器(在非独立系统中)负责将代码加载到内存中,并且可能涉及加载和链接动态链接库(DLL 或共享库,具体取决于操作系统命名法)。无论是 OS 还是 C 运行时责任,通常都会发生以下情况:

    • 堆栈的建立
    • 已初始化静态数据的零初始化
    • 显式初始化静态数据的初始化
    • C 库初始化(通常 stdio 和堆管理需要一些初始化)
    • 对于 C++ 调用静态构造函数。
    • main()argvargc 参数)创建堆栈帧

    例如,在 GCC 和其他一些编译器中,在程序启动之前由您的程序而不是操作系统执行的部分是由一个名为 crt0.o 的单独链接模块执行的。这通常是用汇编程序编写的,默认情况下会自动链接。

    有关更多示例和讨论,请参阅:

    【讨论】:

      【解决方案3】:

      在这个答案中,我调查了 C 程序的入口点位置:Is main() really start of a C++ program?

      当我对 C++ 做一个类似的分析时,结果基本相同,并且正如其他人提到的那样,它是 glibc 的一部分,回溯在main

      #0  main () at hello.cpp:3
      #1  0x00007ffff7be50b3 in __libc_start_main (main=0x5555555551a9 <main()>, argc=1, argv=0x7fffffffbfb8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffbfa8) at ../csu/libc-start.c:308
      #2  0x00005555555550ee in _start ()
      

      因此与 C 程序的行完全相同。

      我认为 C++ 编译器只是调用钩子来实现任何 C++ 特定功能,并且在 C/C++ 中都很好地考虑到了这些因素。

      【讨论】:

        猜你喜欢
        • 2017-05-14
        • 2023-03-21
        • 1970-01-01
        • 1970-01-01
        • 2020-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多