应优先使用 const 或 constexpr 而非 #define 定义常量:#define 无类型、不可调试、易引发副作用;const 提供类型安全和调试支持;constexpr 还支持编译期计算与模板参数。

宏定义 #define 完全绕过类型系统
预处理器在编译前就做文本替换,#define PI 3.14159 后,所有 PI 都被替换成裸数字,编译器根本不知道它该是什么类型。传给函数时可能隐式转成 float、int 甚至指针,毫无警告。
而 const double PI = 3.14159; 会参与类型推导和检查:如果函数形参是 const float&,传入会触发类型不匹配警告;用在模板中也能正确推导出 double 类型。
常见错误现象:#define MAX(a,b) ((a)>(b)?(a):(b)) 在 MAX(i++, j) 中导致 i 自增两次 —— 这类副作用问题宏完全无法防范。
const 变量支持调试器查看和断点
调试器(如 GDB、LLDB、VS Debugger)能识别 const 变量名、显示其值、允许对它设条件断点;但对 #define 宏,调试信息里根本不存在这个符号 —— 它在预处理后就消失了。
立即学习“C++免费学习笔记(深入)”;
这意味着:
- 你在源码里写
if (status == ERROR_TIMEOUT),调试时看不到ERROR_TIMEOUT的值,只能看到一个裸整数(比如1002) - 想在
ERROR_TIMEOUT被赋值处打断点?不可能 —— 它没有地址,也不是变量 - 崩溃堆栈里出现的常量值,无法反查对应宏名,排查成本陡增
现代 C++ 推荐用 constexpr 替代两者
对于需要编译期求值的常量(比如数组大小、模板参数),const 不够用(C++11 前 const int N = 5; 不能用于 int arr[N];),而 #define 又太粗糙。此时应优先选 constexpr:
constexpr int MAX_BUFFER_SIZE = 4096;
constexpr double gravity() { return 9.80665; }
template struct Buffer { char data[N]; };
Buffer buf; // OK: 编译期常量
constexpr 兼具类型安全、调试可见、编译期可用三重优势,且支持函数式计算(只要逻辑满足 constexpr 约束)。
注意:宏仍有不可替代场景,比如条件编译 #ifdef DEBUG、字符串化 STR(x)、或生成重复代码的技巧宏 —— 但这些和“表示常量值”无关。
什么时候还不得不写 #define?
仅当需要以下能力时才用宏定义常量:
- 参与
#if/#ifdef条件编译(const和constexpr无法做到) - 作为头文件卫士:
#ifndef MY_HEADER_H - 生成字符串字面量:
#define STR(x) #x→STR(hello)展开为"hello" - 拼接标识符:
#define CONCAT(a, b) a##b
除此之外,把数值、字符串、类型别名写成 #define,基本等于主动放弃类型检查和调试支持。
真正在意安全性和可维护性,就别让 #define 承担常量语义 —— 它的设计目标从来就不是这个。










