编译期是代码转化为机器指令的预审阶段,由编译器执行宏展开、模板实例化等静态操作;运行期是程序加载执行阶段,涉及内存分配、动态绑定等实际运行行为。

编译期和运行期是 C++ 程序生命周期中两个本质不同的阶段,区分它们的关键在于:谁在执行、做什么事、能访问什么资源、出错时如何反馈。
编译期:代码变成机器指令的“预审”阶段
编译期指从源码(.cpp/.h)经预处理、词法/语法分析、语义检查、优化,最终生成目标文件(.o/.obj)的过程,由编译器(如 clang、g++)主导。此时程序尚未运行,没有栈、堆、全局变量的实际内存,也没有 CPU 指令执行流。
- 做的事包括:宏展开、模板实例化、constexpr 计算、static_assert 断言、类型推导(auto/decltype)、内联函数展开、常量折叠
- 能用的只有编译器已知的静态信息:字面量、类型定义、模板参数、constexpr 表达式结果
- 典型错误如:类型不匹配、未定义标识符、static_assert 失败、模板参数无法推导——这些直接导致编译失败,不生成可执行文件
- 例子:
constexpr int x = 2 + 3;中的2 + 3在编译期就算出结果 5;template中的struct Array { int data[N]; }; N必须是编译期常量
运行期:程序真正“活起来”的执行阶段
运行期指可执行文件被操作系统加载进内存、CPU 开始逐条执行指令的过程。此时有真实的内存布局(栈帧、堆区、数据段)、运行时类型信息(RTTI)、异常处理机制、动态链接等。
- 做的事包括:变量初始化(非 constexpr 的)、new/malloc 分配内存、函数调用(含虚函数动态绑定)、throw/catch 异常、读写文件、网络通信
- 能访问的是运行时才确定的值:用户输入、随机数、系统时间、指针解引用结果、多态对象的实际类型
- 典型错误如:空指针解引用、数组越界、除零、内存泄漏、std::bad_cast——这些不会阻止编译,但会导致程序崩溃或行为未定义
- 例子:
int x = rand();的值只能在运行期确定;Base* p = new Derived(); p->foo();中调用哪个foo由运行时对象实际类型决定
关键分水岭:什么能在编译期决定?
核心判断标准是「是否依赖运行时状态」。C++11 起引入 constexpr、C++14 放宽限制、C++17 加入 if constexpr、C++20 引入 consteval,都是为了把更多逻辑前移到编译期。
立即学习“C++免费学习笔记(深入)”;
- 编译期友好:字面量、枚举值、
constexpr函数/变量、模板非类型参数、std::array大小、std::is_same_v等类型特征 - 运行期专属:
dynamic_cast、typeid、new表达式、std::vector容量、std::string内容、任何涉及 I/O 或系统调用的操作 - 模糊地带需注意:lambda 默认捕获(
[=])不能用于编译期上下文;constexpr函数体内若含运行期分支(如普通 if),整个调用仍可能退化为运行期执行
程序生命周期主线:从源码到进程结束
C++ 程序完整生命周期包含四个紧密衔接的阶段,编译期和运行期分别覆盖其中一部分:
- 预处理期(属编译前期):处理 #include、#define、#ifdef,生成纯文本翻译单元
- 编译期(狭义):翻译单元 → 汇编代码 → 目标文件(.o),完成语法/语义检查与优化
- 链接期(编译后、运行前):合并多个 .o 和库,解析符号引用,生成可执行文件(ELF/PE)
- 运行期:OS 加载程序,初始化全局对象(构造函数)、进入 main()、执行用户逻辑、调用 exit() 或返回、析构全局对象、释放资源
其中,编译期和链接期统称「构建期(build time)」,运行期也叫「执行期(execution time)」。理解这个链条,才能准确判断某段逻辑该放在哪一阶段、用什么语言特性表达最安全高效。











