🔷 第三章 运算符与表达式
📄 一句话概括

一行代码里有好几个运算符时,谁先算由两个规则决定:优先级(分高先算)和结合性(同级时从哪头开始)。本节给你一张金字塔 + 两句口诀——但真正的铁律只有一条:记不清就加括号。

一、优先级:分高先算

前面小节其实一直在用优先级(只是没点破):

int x = 3 + 4 * 2;      // * 高于 + → 3+8=11,不是 14
bool r = 5 > 3 && 2 < 1; // 关系高于逻辑 → (5>3) && (2<1) = 1 && 0 = 0
int y = a << 2 + 1;      // + 高于 << → a << 3(3.1.6 的坑)
cout << 5 > 3;           // << 高于 > → (cout<<5) > 3(3.1.2 的坑)

金字塔主分层(从高到低):

() 括号 · 一元 ! ~ ++ --
* / %          ← 算术二楼
+ -            ← 算术一楼
<< >>
> < >= <=      ← 关系
== !=          ← 比 > < 再低一层!
&&
||
? : 与赋值 = += (很低)
, (垫底)

两句高频口诀:

  1. 算术 > 移位 > 关系 > 逻辑 > 赋值 > 逗号——大方向先抓这条
  2. 细节层的雷:== != 比 < > 低(a < b == c 是 (a<b)==c);&& 比 || 高;<< 比 + 低、比关系高

二、结合性:同级分不出胜负,看方向

两个运算符同优先级时,按结合性决定从哪头开始:

结合性 方向 代表运算符
左结合 从左往右 算术、关系、逻辑、移位、逗号
右结合 从右往左 赋值 = 复合赋值、条件 ? :、一元 !
// 左结合:100 / 5 / 2 从左往右 = (100/5)/2 = 10
//        若从右往左就成 100/(5/2)=50——差远了
cout << 100 / 5 / 2 << endl;      // 10

// 右结合:a = b = 0 从右往左 = a = (b = 0)(3.1.4 连等号的原理)

减法除法不能换序、赋值连等从右往左——这两个场景覆盖了 90% 的结合性考点。

三、铁律:记不清就加括号

优先级表有 50 多行,没有人背全表——资深程序员的武器就是括号:

// 别人能看懂的写法
if ((a > b) && (c < d) || (e == f))
// 编译器能猜、人看懵的写法
if (a > b && c < d || e == f)

两个式子机器执行完全一样,但第一个人和三个月后的你自己都读得懂。规则:

  1. 不同分层的运算符混用 → 加括号(<< 与比较、关系与逻辑混用必加)
  2. 三目、逗号、移位参与复杂式子 → 整体套括号(前面三节的现场教训)
  3. 拿不准 → 上括号,零成本买保险

括号不改变正确答案,只改变出错概率和可读性。编译器不在乎多几对括号,你的同事和你未来的自己在乎。

四、动手 Demo:人肉编译器

先在纸上算出每个式子的值,再跑程序对答案:

#include <iostream>
using namespace std;

int main() {
    cout << 3 + 4 * 2 << endl;              // 11(* 先算)
    cout << 100 / 5 / 2 << endl;            // 10(左结合)
    cout << 5 > 3 << endl;                  // 报错或怪结果:<< 优先级高于 >(演示坑)
    cout << (5 > 3) << endl;                // 1:加括号救回来
    cout << (3 + 4 > 5 && 2 + 1 > 2) << endl;  // (7>5)&&(3>2)=1&&1=1
    int a = 1, b = 2, c = 3;
    a = b = c;                              // 右结合:三个都变 3
    cout << a << b << c << endl;            // 333
    cout << (a << 2 + 1) << endl;           // 3<<3=24(+ 高于 <<)
    return 0;
}

看到什么算成功:11 10 1 1 333 24(cout << 5 > 3 那行按编译器不同可能直接编译不过——这正是教材想让你看到的)。纸上答案和程序输出对不上的地方,就是优先级认知的缺口。

30 秒实验:把 (a > b) && (c < d) || (e == f) 这类式子故意去掉括号,用 a=5,b=3,c=1,d=9,e=5,f=5 跑一遍——结果没变;但把 d 改成 0,去括号版本可能变结果(&& 与 || 谁先结合变了)。

五、常见误区

  1. "== 和 < 是一层的"——不是!== != 比 < > <= >= 低一级。a < b == c 会被算成 (a < b) == c。
  2. "所有运算符都左结合"——赋值和 ? : 是右结合,连等号、链式三目都靠它。
  3. "优先级背下来就安全了"——背不出 50 行表,也没必要背。混用加括号才是真正的安全策略。
  4. "a << 2 + 1 这种写法很酷"——酷给编译器看,坑给读者跳。写代码是写给人看的,顺便给机器执行。
自测四问(点开对答案) 1. `10 + 3 * 4 % 5` 等于多少?——`12`(* 与 % 同级左结合:3×4=12,12%5=2,10+2=12)。 2. `x = y = z = 1;` 靠什么规则执行?——赋值的**右结合**,从右往左依次装。 3. `a < 5 && b > 2` 要加括号吗?——关系已高于逻辑,不加也对;但**建议加**,白送的可读性。 4. `&&` 和 `||` 谁优先级高?——`&&` 高。`a || b && c` 是 `a || (b && c)`。

相关笔记