万字长文,真不是吹的,虽然差了 397 字。
目录
另:如果你按 F11 无法跳到 exe_common.inl,而是程序直接停止了
起因
今天单步调试时按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才是操作系统调用的!
函数/模块调用次序
最后我整理了一下函数/模块使用次序(括号里的是模块,不在括号里的是函数):
- (exe_main.cpp)
- (exe_common.inl)
- (源.cpp)main
- (exe_common.inl)invock_main
- (exe_common.inl)__telemetry_main_return_trigger
- (telemetry.cpp)
- (traceloggingprovider.h)
- (telemetry.cpp)
- (exe_common.inl)
- (utility_desktop.cpp)__scrt_is_managed_app
- (exe_common.inl)exit
嗨!别走!还有呢!
提示:以下代码有点长,可以配合后面的程序注解看看。
以下是“程序不从main函数开始,不从main函数结束”的另一个证明方法(原谅我英语不太好,如果英文有语法错误,请指出):
#include <cstdio>
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
string str("aa");
class my_class
{