const 与 constexpr
更新时间:2026-08-27。本文是
languages/cpp/主题入门层第 4 篇。const在 C++ 里比 C 更受重视:C++ 用const表达不变性、让编译器帮你抓错误。本篇讲const变量、const与指针的组合、以及constexpr编译期常量和它的真正价值。
本文要回答的问题
const变量和 C 的#define常量有什么区别?const int* p和int* const p怎么区分?constexpr和const是一回事吗?编译期计算好在哪?
一、const 变量:类型安全的常量
const int MAX_SIZE = 100;
// MAX_SIZE = 200; // 编译错误:不能给 const 赋值和 C 的 #define MAX_SIZE 100 相比:
| 对比项 | #define(C 宏) | const(C++) |
|---|---|---|
| 类型 | 无类型(纯文本替换) | 有类型,编译器检查 |
| 作用域 | 预处理期,全局可见 | 普通变量作用域 |
| 调试 | 预处理后被替换,看不见 | 有符号,gdb 可查 |
| 作用时机 | 编译前文本替换 | 编译期类型检查 |
const 变量不一定是编译期常量——它可以是运行期算出来的值(比如 const int n = get_input();)。要"编译期就知道"的值,用 constexpr,见下文。
二、const 与指针的四种组合
这是 C/C++ 共同的难点,用"读法"来分:const 修饰紧跟其右的类型,则指针指向的对象不可改;修饰 * 本身,则指针不可改。
| 写法 | 含义 | 能否改对象 | 能否改指针 |
|---|---|---|---|
const int* p | 指向 const int 的指针 | 否 | 是 |
int const* p | 同上(等价写法) | 否 | 是 |
int* const p | 指向 int 的 const 指针 | 是 | 否 |
const int* const p | 两者都 const | 否 | 否 |
记忆口诀:const 在 * 左边修饰"指向的对象",在 * 右边修饰"指针自己"。
int a = 10, b = 20;
const int* p = &a; // *p 不能改
// *p = 30; // 错误
p = &b; // OK:指针自己可以改
int* const q = &a; // q 不能改
*q = 30; // OK:对象可以改
// q = &b; // 错误三、const 的正确性:const 是"契约"
C++ 的核心习惯:能 const 就 const。函数参数声明 const std::string&,意思是"只读借用,不修改",调用方一看签名就知道意图,编译器也会强制:
void print_name(const std::string& name) {
// 这里只能读 name,不能改
}这跟 C 里"传 const char* 表示只读"一脉相承,但 C++ 通过引用 + const 表达了更强的不变性。不写 const 的坏处:调用方不知道你会不会改数据,只能防着,代码难以推理。const 是写给读者和编译器看的契约,不是运行时开销——编译后和普通变量没区别。
四、constexpr:编译期常量
constexpr(C++11 起)表示"这个值/函数可以在编译期求值":
constexpr int KB = 1024;
constexpr int MB = KB * 1024; // 编译期算出 1048576
constexpr int square(int x) { // constexpr 函数
return x * x;
}
int arr[square(5)]; // 编译期数组大小:合法(C++11 起)constexpr 的真正价值:把能提前算的都提前算掉——数组大小、模板参数、switch 分支——运行时零开销。编译期计算出错会直接编译失败,等于把 bug 提前拦在运行之前。
注意区别:
const | constexpr | |
|---|---|---|
| 修饰对象 | 不可变的变量 | 编译期常量 |
| 求值时机 | 运行期 | 编译期 |
| 典型用途 | 只读参数、只读引用 | 数组大小、模板参数、编译期计算 |
| 组合 | 可一起用 | 更严格 |
一个 const 变量如果初始值是编译期可求值的字面量,编译器常优化成常量,但标准不保证;constexpr 是明确要求编译期求值,语义更强。
五、const 成员函数(预告)
类里的 const 成员函数表示"这个函数不修改对象状态":
class Point {
int x, y;
public:
int getX() const { return x; } // const 成员函数
};const Point p; 只能调用 const 成员函数——这就是用类型系统强制"只读对象"的体现。详细内容在入门篇const 成员函数和类与对象。
六、与本站主线衔接
constexpr的编译期计算和-O2优化如何配合(热点消除),见 L4 编译器选项;- 编译期计算进阶(constexpr 函数、模板元编程),见专家层 constexpr 与编译期计算;
- C 的 const 与指针,见 C 语言 const 与指针。
一句话总结
const 表达"不变性"——const 变量类型安全(优于 #define)、const 在 * 左修对象右修指针、函数参数能 const 就 const(是契约零开销);constexpr 更进一步,把值固定在编译期;在 C++ 里 const/constexpr 不是可选项,而是让编译器帮你抓错的默认姿势。
上一篇:变量与基本类型 下一篇:std::string 入门