优先用 constexpr;若依赖运行时则用 extern const;C++17 起推荐 inline constexpr,避免声明/定义分离和 ODR 问题;禁用 #define。

全局常量该用 constexpr 还是 const?
在 C++17 及以后,定义跨文件可用的全局常量,优先用 constexpr;如果值依赖运行时(比如从配置读取),才退而求其次用 extern const。前者能进头文件、被内联、不占数据段,后者容易因 ODR(One Definition Rule)出错。
-
constexpr变量默认有内部链接(static),直接写在头文件里安全,多个 TU 包含也不会重定义 -
const变量若没加extern,也默认内部链接;但一旦加了extern,就必须在某个 .cpp 里定义一次,否则链接失败 - 数值型、字符串字面量、简单结构体(满足字面类型要求)都可
constexpr;std::string不行,得用std::string_view
示例:
// config.h<br>constexpr int MAX_RETRY = 3;<br>constexpr std::string_view API_HOST = "https://api.example.com";
extern const 跨文件变量怎么避免链接错误?
这是最容易栽跟头的地方:声明和定义分离没做对,或者头文件里误写了定义。
- 头文件中只放
extern const声明(不带初始化),例如:extern const double PI; - 必须且只能在一个 .cpp 文件里写定义(带初始化):
const double PI = 3.1415926; - 漏掉 .cpp 中的定义 → 链接时报
undefined reference to 'PI' - 在头文件里写了
const double PI = 3.1415926;(没加extern)→ 每个包含它的 .cpp 都生成一份,违反 ODR,链接时报multiple definition of 'PI'
用 inline constexpr 是不是更省心?
是,C++17 引入的 inline 变量让跨文件常量彻底告别“声明/定义分离”这套老流程,尤其适合复杂类型或需要构造函数的场景。
立即学习“C++免费学习笔记(深入)”;
-
inline constexpr允许在头文件中定义并初始化,编译器保证只有一份实体,且仍可内联优化 - 支持非字面类型,比如
inline constexpr std::array<int> DEFAULTS = {1, 2, 3};</int> - 注意:
inline关键字不能省,光写constexpr不够;C++14 及以前不支持,得用传统extern方式
示例:
// utils.h<br>inline constexpr auto HTTP_TIMEOUT_MS = 5000;<br>inline constexpr std::string_view LOG_LEVEL = "INFO";
为什么别用 #define 定义全局常量?
它不参与类型检查、不进调试符号、不能取地址、宏替换可能意外污染作用域——现代 C++ 几乎没有理由选它。
- 调试器看不到
#define MAX_SIZE 1024的值,但能看到constexpr int MAX_SIZE = 1024; -
#define是纯文本替换,MAX_SIZE + 1没问题,但MAX_SIZE * sizeof(int)如果忘了括号就出错 - 模板推导、
auto、decltype都无法识别宏,但能完美处理constexpr变量
真要兼容极老编译器(如 VS2013),再考虑降级方案,否则一律绕开 #define。
跨文件常量最麻烦的从来不是语法,而是链接阶段悄无声息地失败——要么多份定义,要么根本找不到。盯住 inline 和 constexpr 的组合,把东西全塞头文件里,反而最稳。










