前面的常量都是"直接写出来的值",这一节讲给常量起名字——符号常量。两种做法:const(const double PI = 3.14159;,有类型、编译器帮你检查,推荐)和 #define(#define PI 3.14159,本质是预处理阶段的文本替换,没有类型,老代码里常见)。另外还有布尔常量 true / false——看着是"真/假",存进去就是 1 和 0。
一、符号常量:为什么给常量起名字
cout << 3.14159 * r * r << endl; // 这个 3.14159 是什么?
代码里突然冒出一个数字(行话叫魔法数字),三个月后连你自己都不知道它是干嘛的。改成:
const double PI = 3.14159;
cout << PI * r * r << endl; // 一眼看懂:圆的面积
三个好处:
- 自解释:名字说明含义
- 一改全改:税率从 0.13 变 0.09,只改定义那一行
- 防手误:不用在十几个地方各敲一遍
3.14159
二、两种做法对比
做法一:const(推荐)
const double PI = 3.14159; // 定义时必须给值
const int MAX_SIZE = 100;
PI = 3.14; // ✗ 报错:不能给常量赋值
- 有类型(
double、int),编译器能帮你检查 - 有作用域(写在谁的花括号里,就只在哪儿有效)
- 写错立刻报错,调试时还能看到它的值
- 教材与主流实践都推荐它
做法二:#define(预处理宏)
#define PI 3.14159 // 注意:末尾不加分号,也不写 =
#define MAX_SIZE 100
cout << PI << endl; // 编译前 PI 已被换成 3.14159
- 本质是预处理阶段的"查找替换":预处理器看到
PI三个字母,直接换成3.14159,编译器压根不知道有过PI这个名字 - 没有类型:
#define出来的东西不参与类型检查,容易出怪错 - 因此有一个经典坑:
#define MAX 100;(末尾加了分号)→ 替换后变成int a = 100;;,多数情况能过但属于隐患;换成if (a > MAX)就可能直接报错
const |
#define |
|
|---|---|---|
| 谁处理 | 编译器 | 预处理器(编译之前) |
| 有类型吗 | 有 | 没有 |
| 检查严格吗 | 严格 | 不检查 |
| 能调试吗 | 能(看得到名字) | 看不到(早被替换) |
| 结尾 | 要分号 | 不要分号 |
| 建议 | 优先用这个 | 认识它、读得懂老代码即可 |
命名习惯:符号常量习惯全大写(PI、MAX_SIZE、TAX_RATE),一眼和普通变量区分开。
三、布尔常量
bool isOk = true; // 真
bool isDone = false; // 假
true和false是 C++ 的关键字(不是变量名,不能给变量起这两个名字)- 底层就是 1 和 0:
cout << true;默认输出 1 - 它的正经用武之地是判断条件(第 4 章
if的主角),现在认识一下就行
小知识:C 语言里原本没有 true/false(只有 1 和 0),是 C++ 引入的。所以在看 C 的老代码时,看到 if (flag == 1) 别奇怪。
四、动手 Demo:三个实验看清 const 与 #define 的区别
新建 constdemo.cpp:
#include <iostream>
using namespace std;
#define MAX_SIZE 100 // 宏常量:不加分号
int main() {
const double PI = 3.14159; // const 常量:要加分号
cout << "PI = " << PI << endl;
cout << "MAX_SIZE = " << MAX_SIZE << endl;
// PI = 3.14; // ← 打开这行试试
return 0;
}
实验一:把 PI = 3.14; 那行的注释打开,编译。
→ 预期报错类似 assignment of read-only variable 'PI'——"read-only"就是"只读",即常量不许改。
实验二:给 #define MAX_SIZE 100 末尾加一个分号,编译。
→ 观察报错或警告(有的编译器能过,有的会报奇怪错误)。这个实验告诉你:宏后面那个分号会一起被替换进去。
实验三:把 #define MAX_SIZE 100 改成 #define MAX_SIZE "一百",再 cout << MAX_SIZE;。
→ 竟然能输出 一百!因为 #define 只是文本替换,它根本不管"100 应该是数字"。这就是"没有类型检查"的真相。
看到什么算成功:三个实验都能说出"为什么会这样"。
30 秒实验:把 cout << true << " " << false << endl; 加进去,看输出是不是 1 0。
五、常见误区
- "
const和#define差不多,用哪个都行"——差得多。#define没有类型检查,出错时报错信息会指向被替换后的怪代码,非常难查。新代码一律优先const - "
#define后面要加分号"——不要。加了分号,分号也会被一起替换进去,可能引发莫名其妙的错误 - "
const常量可以先定义后赋值"——不行。定义时必须给初始值:const int A;会报错 - "
true、false是普通变量名"——它们是关键字,不能当变量名(int true = 1;直接报错)
自测四问(点开对答案)
1. `const` 和 `#define` 的本质区别?——`const` 由**编译器**处理、**有类型**、会做检查;`#define` 由**预处理器**做**纯文本替换**、没有类型、不检查。 2. 为什么优先用 `const`?——有类型、能调试、报错清楚、有作用域;`#define` 出错时定位困难。 3. `#define` 末尾能不能加分号?——**不能**,分号会跟着被替换进去,可能引发错误。 4. 布尔常量 `true` / `false` 在内存里是什么?——**1 和 0**(`cout << true` 输出 1)。- ☑ 变量
相关笔记
- 常量及符号 —— 五类常量总览
- #include 指令 —— 另一类预处理指令
- 布尔类型 ——
bool类型的正式讲解