程序不是从main开始运行的,操作系统先创建进程、映射地址空间、加载动态库、初始化全局变量和静态对象、准备argc/argv,再由运行时启动函数(如_start或maincrtstartup)调用main。

程序不是从 main 开始运行的,这是新手最容易误解的一点。真正启动时,操作系统先加载程序、分配栈和堆,再由 C++ 运行时库(如 mainCRTStartup 或 _start)完成初始化,最后才调用你的 main 函数。
程序启动前发生了什么
双击 .exe 或执行可执行文件后,操作系统不会直接跳进你写的 main。它要先做几件关键的事:
- 创建进程,映射虚拟地址空间(包括栈、堆、代码段、数据段等)
- 加载依赖的动态库(比如
msvcp140.dll或libc++.so) - 为全局变量和静态对象分配内存,并执行构造函数(注意:这发生在
main之前) - 解析命令行参数,准备好
argc和argv - 调用 C 运行时初始化函数(例如 Windows 下的
mainCRTStartup),再由它调用你的main
你可以把 main 看作“导演喊 Action”的那一刻,但布景、灯光、演员就位全在它之前完成了。
为什么全局变量能比 main 先初始化
因为 C++ 标准规定:所有定义在全局/命名空间作用域的变量(含 static 局部变量),其初始化必须在 main 执行前完成。编译器会把这些初始化逻辑插入到运行时启动代码中。
例如这段代码:
int global = 42;
class A { public: A() { std::cout
<p>输出一定是:</p>
<pre class="brush:php;toolbar:false;">A constructed
in main
这说明 a 的构造函数在 main 进入前就执行了——不是编译器“猜的”,而是链接时被写进了初始化节(.init_array 或类似机制)。
main 返回后程序还没结束
main 函数返回后,控制权交还给运行时库,它会:
- 调用所有全局对象的析构函数(按构造逆序)
- 刷新并关闭标准 I/O 流(如
std::cout缓冲区) - 调用
exit()相关清理逻辑(比如执行atexit注册的函数) - 最终向操作系统返回退出码,进程终止
所以如果你在 main 末尾加了 std::cout 却没看到输出,很可能是缓冲区没刷新——加 <code>std::endl 或 std::flush 就行。这不是 bug,是运行时收尾阶段的正常行为。
真正容易被忽略的是:整个生命周期里,main 只是中间一段可控的执行区间;前后两端都由运行时库接管,而这些部分恰恰决定了全局对象能否正确构造/析构、资源是否泄漏、甚至程序能否稳定退出。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











