【C++】006、#define与const的区别

一、核心区别

1)处理阶段不同:

  • #define宏定义是在预处理阶段,进行文本替换操作,属于预处理器管辖

  • const是编译阶段的类型化常量,属于编译器管辖

2)类型安全等方面不同:

  • 他们在类型安全,作用域,内存分配和调试体验上都有着本质差异

二、六大区别对照表

|-----------|---------------------------|-------------------------|
| 对比维度 | #define宏常量 | const常量 |
| 处理阶段 | 预处理阶段(文本替换) | 编译阶段(词法分析,语法检查) |
| 类型检查 | 无类型检查(字符串替换,不关心类型) | 有严格的类型检查(编译器会对类型进行检查匹配) |
| 内存分配 | 不分配内存(展开为字面量,存在于符号表中) | 分配内容(本质是变量,存放在数据段或栈中) |
| 作用域 | 无视C++作用域 | 遵循C++作用域规则 |
| 调试体验 | 无法调试(宏在预处理阶段已被替换,找不到相关信息) | 可以调试(在符号表中有名字,可进行查看与修改) |
| 副作用风险 | 文本替换会导致运算符优先级错误 | 无副作用 |

三、文本替换的副作用

  • 代码实现
cpp 复制代码
#define MULTIPLY(a, b) a * b
#define SQUARE(x) x * x

int main() {
    int x = 5;
    int result1 = SQUARE(x + 1); 
    // 宏展开:x + 1 * x + 1 = 5 + 1*5 + 1 = 11,而不是期望的 36!

    int result2 = 2 * MULTIPLY(3, 4);
    // 宏展开:2 * 3 * 4 = 24(这里恰好对),但如果是 MULTIPLY(3+1, 4) 同样会出问题。

    // ✅ const 常量绝对安全
    const int y = 5;
    int result3 = (y + 1) * (y + 1); // 编译器正常求值,结果36
}

四、在底层存储上的区别

  • #define:不占用数据段内存,编译器在预处理阶段把符号替换成数据字面量

  • const:本质上是变量,全局const存储在.rodata段(只读数据段),局部const存储在栈(stack)上

五、现代C++实践中的#define替换方法

为规避宏定义的副作用,现代C++代码实践中不建议继续使用#define,改用替代方案

  • 编译器常量,使用constexpr

  • 运行时常量,用const

  • #define使用场景,只在头文件防卫,条件编译和日志/断言中使用。