C++ 程序真的是从main函数开始/结束的吗?

万字长文,真不是吹的,虽然差了 397 字。

目录

起因

经过

exe_common.inl

telemetry.cpp

traceloggingprovider.h

又回到telemetry.cpp里了? 

又跳到exe_common.inl里了

utility_desktop.cpp

exe_common.inl他又来了

exit函数——程序的退出

继续探索——main函数的调用者

exe_common.inl

exe_main.cpp

结果

结论

函数/模块调用次序

嗨!别走!还有呢!

另:如果你按 F11 无法跳到 exe_common.inl,而是程序直接停止了

所以,CRT 在main函数调用前/结束后,做了什么?

初始化 CRT

__try __except

上锁,检查,解锁

处理全局构造函数,注册全局析构函数。

调用 main 函数。

收尾

__scrt_uninitialize_crt

__except块

控制流返回到__scrt_common_main

控制流返回到 mainCRTStartup

最后返回到了 kernel32.dll

G++


起因

今天单步调试时按F11按多了(我更习惯用F11而不是F10),main函数结束后程序忽然跳到了exe_common.inl里面!

于是兴致大起,写了一个比Hello World还简单的程序来做实验:

int main()
{
    return 0;
}

简单不?这个不是重点,我们现在开始调试

经过

exe_common.inl

按4下F11就跳到了exe_common.inl里

telemetry.cpp

又按4下F11,VS提示未找到telemetry.cpp,于是手动创建了一个空的, 看看能不能迷惑住VS,居然真的迷惑住了 

||ヽ(* ̄▽ ̄*)ノミ|Ю

traceloggingprovider.h

又按了大约10次F11,VS又提示需要 traceloggingprovider.h,于是又创建了一个(#^.^#)

又回到telemetry.cpp里了? 

又按了5下F11,它跳回了telemetry.cpp里面。又按了两下,他又跳到了exe_common.inl中。

又跳到exe_common.inl里了

又按两下,跳到utility_desktop.cpp里了 

utility_desktop.cpp

再按11下,又跳回(exe_common.inl)去了。

exe_common.inl他又来了

再次跳到exe_common.inl里面时,我有一种不祥的预感:下一行就是exit函数了o(╥﹏╥)o

exit函数——程序的退出

再按两下,运行到了函数调用exit(main_result);里面,跳到这里程序才算退出了。

继续探索——main函数的调用者

exe_common.inl

但我的实验还没结束,我再次定位到exe_common.inl里,发现main函数是在那里被调用的:

static int __cdecl invoke_main() throw()
{
    return main(__argc, __argv, _get_initial_narrow_environment());
}

然后启动搜索大法(注意是所有的 Visual C++ 目录),发现有4个源文件都导入了这个模块:

  • exe_main.cpp
  • exe_wmain.cpp
  • exe_winmain.cpp
  • exe_wwinmain.cpp

exe_main.cpp

要的当然是exe_main.cpp啊!点进去一看,(不算空行和注释)居然只有6行!

#define _SCRT_STARTUP_MAIN
#include "exe_common.inl"
extern "C" int mainCRTStartup()
{
    return __scrt_common_main();
}

结果

结论

然后再次启动搜索大法,没搜到那里使用exe_main.cpp,于是得出结论:

main函数不是操作系统调用的,是exe_common.inl调用的!

exe_common.inl也不是操作系统调用的,是exe_main.cpp调用的!

exe_main.cpp才是操作系统调用的!

函数/模块调用次序

最后我整理了一下函数/模块使用次序(括号里的是模块,不在括号里的是函数):

  1. (exe_main.cpp)
  2. (exe_common.inl)
  3. (源.cpp)main
  4. (exe_common.inl)invock_main
  5. (exe_common.inl)__telemetry_main_return_trigger
  6. (telemetry.cpp)
  7. (traceloggingprovider.h)
  8. (telemetry.cpp)
  9. (exe_common.inl)
  10. (utility_desktop.cpp)__scrt_is_managed_app
  11. (exe_common.inl)exit

嗨!别走!还有呢!

提示:以下代码有点长,可以配合后面的程序注解看看。

以下是“程序不从main函数开始,不从main函数结束”的另一个证明方法(原谅我英语不太好,如果英文有语法错误,请指出):

#include <cstdio>
#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

string str("aa");
class my_class
{
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值