3. 常量与运算符:字面常量、const常量、算术运算符、赋值运算符
大家好,我是老刘。今天咱们聊聊C++里最基础、但也是最容易踩坑的两个东西——常量和运算符。你别看它们简单,我见过太多项目因为常量定义不规范、运算符优先级搞错,导致线上bug的案例。嗯,咱们一个一个来。
3.1 字面常量:代码里的“硬数字”
字面常量,说白了就是你直接写在代码里的那些值。比如 42、3.14、'A'、"hello"。它们就是字面意思,不能再变了。
常见字面常量类型:
| 类型 | 示例 | 说明 |
|---|---|---|
| 整型 | 42 0xFF 077 | 十进制、十六进制、八进制 |
| 浮点型 | 3.14 1.2e5 | 小数或科学计数法 |
| 字符型 | 'A' '\n' | 单个字符,转义字符 |
| 字符串 | "hello" | 双引号括起来的字符序列 |
| 布尔型 | true false | C++11起推荐用 |
我个人习惯,能用 const 或枚举代替的字面常量,绝不直接写数字。为什么?你想想看,代码里突然冒出一个 86400,鬼知道它代表什么?是秒数?是行数?还是某个魔法数字?
我的小技巧: 项目中我经常用 using namespace std::literals 来写更语义化的字面量,比如 24h、60s,代码可读性直接拉满。
3.2 const常量:让编译器帮你“盯”着
const 关键字,说白了就是告诉编译器:“这个值,你帮我看着,谁也别想改它。” 一旦初始化,后面再赋值就编译报错。
const int MAX_USERS = 1000;
// MAX_USERS = 2000; // 编译错误!const变量不能修改
const double PI = 3.1415926;
double radius = 5.0;
double area = PI * radius * radius;
我在项目中遇到过最经典的坑:有人把 const 变量定义在头文件里,结果多个cpp文件包含后,链接时报重复定义。嗯,这里要注意——const 变量默认是内部链接的,但如果加了 extern,就要小心了。
避坑指南: 我曾经在维护一个老项目时,发现有人用 #define PI 3.14 而不是 const double PI = 3.14。结果宏定义没有类型检查,在表达式里隐式转换出了大问题。记住:C++里能用 const 就别用 #define。
3.3 算术运算符:加减乘除那些事儿
算术运算符大家都熟:+ - * / %。但有几个细节,新手经常翻车。
- 整数除法会截断:
5 / 2结果是2,不是2.5。想要浮点结果,至少一个操作数得是浮点型。 - 取模
%只用于整数:5.5 % 2编译报错。浮点数取余用fmod()。 - 自增自减的前置后置:
++i先加后用,i++先用后加。性能上,前置略优(少一次临时对象构造)。
int a = 10, b = 3;
int c = a / b; // c = 3
int d = a % b; // d = 1
double e = 10.0 / 3; // e ≈ 3.3333
int x = 5;
int y = ++x; // x=6, y=6
int z = x++; // x=7, z=6
我的经验: 在循环里,我习惯用 ++i 而不是 i++。虽然现代编译器优化后两者性能一样,但这是个好习惯。另外,别在同一个表达式里多次修改同一个变量,比如 i = i++ + ++i——这是未定义行为,不同编译器结果可能不同。
3.4 赋值运算符:不只是 =
赋值运算符 = 是最常用的,但C++还提供了一组复合赋值运算符:+= -= *= /= %= 等。它们能让代码更简洁,也更容易读。
int score = 100;
score += 10; // 等价于 score = score + 10; score=110
score -= 20; // score=90
score *= 2; // score=180
score /= 3; // score=60
score %= 7; // score=4
赋值运算符有个容易忽略的点:赋值表达式本身也有值。比如 a = b = c = 5 是合法的,从右向左依次赋值。但我不建议这么写,可读性太差。
避坑指南: 我曾经在代码审查时看到有人写 if (x = 5),本意是判断 x == 5,结果写成了赋值。赋值表达式返回的是赋的值(非零即为true),所以条件永远成立。这个bug藏了两个月才被发现。我的建议是:如果确实要写赋值+判断,显式写成 if ((x = getValue()) != 0),让意图一目了然。
3.5 知识体系总览
下面这张图,是我自己梳理的本章知识结构。你可以把它当作一个快速索引,哪里忘了就回来瞄一眼。
3.6 综合示例:计算圆的周长和面积
最后,咱们来个综合小例子,把今天讲的东西串起来。这个例子我在培训新人时经常用,简单但能覆盖不少知识点。
#include <iostream>
using namespace std;
int main() {
// const常量定义
const double PI = 3.1415926;
// 字面常量 + 变量
double radius = 5.0;
// 算术运算符
double circumference = 2 * PI * radius;
double area = PI * radius * radius;
// 复合赋值运算符
radius += 1.0; // 半径增加1
cout << "原始半径: 5.0" << endl;
cout << "周长: " << circumference << endl;
cout << "面积: " << area << endl;
cout << "增加后的半径: " << radius << endl;
return 0;
}
输出结果:
原始半径: 5.0
周长: 31.4159
面积: 78.5398
增加后的半径: 6
你看,PI 用 const 定义,保证了它不会被意外修改。2 * PI * radius 里混合了字面常量、const 常量和变量。最后 radius += 1.0 是复合赋值运算符的典型用法。代码简洁、意图清晰,这就是好的C++风格。
最后说一句: 常量和运算符是C++的“砖瓦”,看似简单,但用好了能让代码既安全又易读。我见过太多项目因为常量定义混乱、运算符滥用导致维护成本飙升。记住:写代码是给人看的,顺便让机器执行。多用 const,少写魔法数字,运算符别炫技——这是我从多年项目里总结出来的血泪教训。