17370845950

C++ 怎么定义常量 C++ #define与const使用场景对比【代码】
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) #xSTR(42) 展开为 "42"
  • 需要拼接 token:#define CONCAT(a, b) a##bCONCAT(foo, _bar)foo_bar

const#define 安全得多

#define PI 3.14159 看似简单,但它是全局文本替换,没有类型、无作用域、不进调试符号表,且容易因括号缺失出错(如 #define SQUARE(x) x*x 遇到 SQUARE(a + b) 就崩成 a

+ b*a + b)。

const 则是真正的变量(或引用),受编译器类型检查和作用域控制:

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;其余所有数据常量,都该交给 constconstexpr 管理。