应优先使用 inline 函数或 constexpr 模板函数,仅在需编译期文本拼接(如含 FILE 的日志宏)时用 #define;因 inline 保障类型安全、单次求值、可调试,而宏无类型检查、参数多展开、不可调试、作用域失控。

define 是文本替换,不经过编译器类型检查
#define 在预处理阶段直接做字符串替换,完全绕过语法解析和类型系统。比如写 #define SQUARE(x) x * x,调用 SQUARE(a + b) 会变成 a + b * a + b,结果错得离谱——因为没加括号,也没做表达式求值顺序保护。
常见错误还包括:
- 宏参数被多次展开(如
SQUARE(++i)导致i自增两次) - 无法调试:调试器看不到宏,断点打不进去,变量名也查不到
- 作用域失效:宏是全局的,不受命名空间或类作用域约束
inline 是编译器建议,有完整函数语义
inline 关键字只是向编译器提出“这个函数适合内联”的请求,是否真内联由编译器根据调用频率、函数体大小、优化等级等综合判断。它保留函数的所有特征:类型安全、参数求值一次、支持重载、可被调试、遵守作用域规则。
例如:
inline int square(int x) { return x * x; }传入 square(++i) 时,++i 只执行一次;传入浮点数会触发编译错误(类型不匹配),而不是静默生成错误代码。
立即学习“C++免费学习笔记(深入)”;
性能差异实际取决于编译器和上下文
现代编译器(GCC/Clang/MSVC)在 -O2 或更高优化级别下,对 inline 函数的内联决策远比人靠谱。手动加 inline 往往没用,反而可能干扰编译器优化(比如强制内联一个大函数导致代码膨胀)。
而宏看似“一定展开”,但:
- 编译器仍可能对宏展开后的代码做冗余消除、常量传播等优化
- 宏本身不带调试信息,出问题时难以定位真实逻辑位置
- 模板函数 +
constexpr(C++11 起)往往比宏更安全且同样零开销
简单函数(如 getter)几乎总会被内联,无论是否写 inline;复杂逻辑写 inline 也大概率被忽略。
该用哪个?看目的不是看“快不快”
需要类型安全、可调试、可重载 → 无条件选 inline 函数(或 constexpr 函数)
必须做编译期文本拼接(如日志宏带 __FILE__ 和 __LINE__)→ 只能用 #define,但应尽量限制在必要场景
想写通用计算(如泛型平方)→ 用模板函数,不是宏也不是普通 inline:
templateconstexpr T square(T x) { return x * x; }
宏的“性能优势”在绝大多数场景下不存在,反而把维护成本和出错概率推高——真正影响性能的是算法、缓存局部性、分支预测,不是这一行展不展开。










