Menu

C++ 运算符:算术、比较、逻辑运算符等

学习 C++ 运算符:算术、比较、逻辑、赋值和位运算符,以及整数除法、优先级和短路求值方面的陷阱。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

运算符的作用

运算符是对一个或多个值执行某种操作的符号,这些值叫作操作数。你其实已经用过一个了:把值绑定到变量上的 =。C++ 提供了丰富的运算符,用于数学计算、比较、逻辑和位操作,也有几处容易让新手栽跟头的地方。

上一页你看到了 const 如何把一个值固定下来。而运算符是你计算要存储的值的方式,无论这些值是不是常量。下面我们逐一介绍你每天都会用到的几类运算符。

算术运算符

五个算术运算符是 +、-、*、/ 和 %(取模,即除法的余数):

最大的陷阱就在商里。17 / 5 打印的是 3,而不是 3.4。当两个操作数都是整数时,/ 执行整数除法,丢弃小数部分:它是向零截断,而不是四舍五入。如果你想要真正的小数结果,至少要有一个操作数是浮点数:

% 运算符只能用于整数。对 double 使用 % 会导致编译错误,浮点数取余请使用 <cmath> 中的 std::fmod。

赋值与复合赋值运算符

单个 = 表示赋值,而不是比较。C++ 还提供了把运算和赋值合二为一的复合形式,这样就不必重复写变量名:

一个经典又让人头疼的错误,是在条件中本想写 == 却写成了 =。if (x = 0) 会把 0 赋值给 x,然后判断结果(为假),而不是进行比较。开启警告后,现代编译器会对此发出警告,所以请保持 -Wall 开启,并认真对待这个警告。

比较运算符

比较运算符提出一个是或否的问题,结果是一个 bool(true 或 false):

默认情况下,cout 把 bool 打印为 1 或 0。向流输出一次 boolalpha,之后这个流就会改用 true/false 这两个单词。

一个隐蔽的陷阱:不要像 1 < x < 10 这样连续比较。它会被解析为 (1 < x) < 10:第一个比较得到一个 bool(0 或 1),再拿它和 10 比较,所以整个表达式几乎总是 true。应该写成 1 < x && x < 10。

逻辑运算符与短路求值

&&(与)、||(或)和 !(非)用于组合布尔表达式。前两个具有短路特性:一旦结果确定,就停止求值。

check("A") 和 check("B") 都没有执行,这就是短路求值。它不只是一种优化,更是一种工具。你可以放心地写 if (ptr != nullptr && ptr->ready),因为只有当 ptr 不为空时才会执行到 ptr->ready,从而避免解引用悬空指针。

自增与自减

++ 加一,-- 减一。它们都有前置和后置两种形式,当你使用表达式的结果时,两者的区别就很重要:

如果你只想要自增这个副作用(比如在 for 循环中),优先使用 ++i。对普通的 int 来说两者没有区别,但对于迭代器这样较重的类型,后置自增必须先复制旧值,这是白白浪费的工作。

还有一个警告:不要在同一个表达式中两次修改同一个变量,比如 i = i++ + 1; 或 arr[i] = i++;。这些更新的顺序是不确定的,结果是未定义行为。每条语句中,每个变量只修改一次。

位运算符与优先级

在底层编程中会用到位运算符:&(按位与)、|(按位或)、^(按位异或)、~(按位取反),以及移位运算符 << 和 >>。

注意:<< 和 >> 同时也是 cout 上的流运算符。在 cout 语句中,通常需要给移位运算加上括号,否则编译器会把它当作流插入。

最后,当你混用多个运算符时,优先级决定了谁先结合。和数学中一样,* 和 / 比 + 和 - 结合得更紧,所以 2 + 3 * 4 等于 14。比较运算符的优先级低于算术运算符,逻辑运算符 &&/|| 更低。拿不准的时候,不要去背完整的优先级表,加上括号就好。(a + b) * c 比指望读者记住规则要清楚得多。

下一步:类型转换

上面你看到 (double)a / b 强制把整数变成了浮点数除法。这就是类型转换(cast):有意地把一个值从一种类型转换成另一种类型。下一页我们会介绍 C++ 的各种转换工具,从隐式提升到 static_cast,以及每种转换在什么情况下是安全的。

常见问题

C++ 中有哪些运算符?

C++ 的运算符分为算术运算符(+ - * / %)、比较运算符(== != < > <= >=)、逻辑运算符(&& || !)、赋值运算符(= += -= 等)、自增/自减运算符(++ --)和位运算符(& | ^ ~ << >>)。此外还有三元运算符 ?:,以及 sizeof 等少数其他运算符。

为什么 C++ 中 5 / 2 等于 2?

因为两个操作数都是 int,所以 / 执行的是整数除法,小数部分会被直接舍弃,而不是四舍五入。要得到 2.5,至少要让一个操作数是浮点数:5.0 / 2 或 5 / 2.0。

C++ 中 ++i 和 i++ 有什么区别?

两者都会给 i 加 1。++i(前置自增)先自增,再返回新值;i++(后置自增)先返回旧值,再自增。如果你只关心自增这个副作用,优先使用 ++i。

Coddy 编程语言插图

和 Coddy 一起学编程

开始