C++中优先使用const或constexpr,仅在条件编译、头文件卫士、字符串化或token拼接等预处理不可替代场景才用#define。

直接说结论:C++ 中优先用 const(或 constexpr),#define 仅在宏替换不可替代的场景下使用,比如条件编译、头文件卫士、或字符串化/拼接。
什么时候必须用 #define
预处理器不关心类型、作用域和语法,只做文本替换。所以以下情况绕不开 #define:
-
#ifdef/#ifndef条件编译——const变量无法参与预处理判断 - 头文件卫士:
#ifndef MY_HEADER_H…#define MY_HEADER_H - 需要把标识符转成字符串:
#define STR(x) #x→STR(42)展开为"42" - 需要拼接 token:
#define CONCAT(a, b) a##b→CONCAT(foo, _bar)得foo_bar
const 比 #define 安全得多
#define PI 3.14159 看似简单,但它是全局文本替换,没有类型、无作用域、不进调试符号表,且容易因括号缺失出错(如 #define SQUARE(x) x*x 遇到 SQUARE(a + b) 就崩成 a + b*a + b)。
const 则是真正的变量(或引用),受编译器类型检查和作用域控制:
立即学习“C++免费学习笔记(深入)”;
const double PI = 3.14159; // 类型明确,作用域可控
const int MAX_SIZE = 1024; // 编译期常量(C++17 起可作数组维度)
constexpr int fib(int n) { ... } // C++11 起支持编译期计算-
const变量有地址,能取地址、传引用、用于模板非类型参数(C++17+) -
constexpr还能保证编译期求值,比const更强(如constexpr int arr[N]中N必须是constexpr) - 调试时能看到
PI的值;#define在调试器里根本搜不到
字符串字面量和数组长度的典型陷阱
定义字符串常量时,#define MSG "hello" 和 const char* MSG = "hello"; 行为不同:
-
#define是纯文本替换,多次使用可能生成多份副本(虽然现代编译器常优化) -
const char*是指针,指向同一字符串字面量;若要确保内容不可改且避免指针语义,该用const char MSG[] = "hello";—— 这会分配数组,且长度可推导:sizeof(MSG)包含末尾\0 - 定义数组大小时:
const int N = 10;在 C++11 前不能用于int arr[N];(VLA 不合法),必须用constexpr int N = 10;或#define N 10
真正复杂的地方不在语法,而在「是否需要预处理介入」——一旦涉及 #if、头文件包含控制、或 token 操作,就只能上 #define;其余所有数据常量,都该交给 const 或 constexpr 管理。










