C语言运算符优先级这个东西,我见过太多人栽跟头了。学了几个月指针都玩得飞起,结果一个 a = b & 0xFF == c 直接把运行结果搞崩,查了半天才发现是 == 比 & 的优先级高。这不是智商问题,是知识点没串起来。今天我就用实际开发里踩过的坑,把优先级这层窗户纸捅破,让C语言运算符从“背了又忘”变成“再也忘不掉”。
这篇文章适合刚入门C语言的学生、准备笔试面试的求职者,以及写了几年代码却总在表达式的坑里翻车的嵌入式开发。核心就一句话:优先级不是让你背的,是让你用的。搞懂它背后的语法逻辑和结合方向,你就掌握了阅读C表达式的钥匙。
1. 运算符优先级的本质:为什么它总在坑你
1.1 优先级不是“数学规则”,是“语法规则”
很多人下意识把C语言的运算符优先级当成数学运算顺序,比如先乘除后加减,觉得理所当然。我一开始也这么想,直到遇到位运算、移位、逻辑运算混在一起时,才发现这个认知会带来灾难。
C语言的运算符优先级,本质是编译器语法分析器对表达式结构的规定。它决定了表达式应该如何被“切分”成子表达式。这跟数学规则有关联,但绝不是一回事。数学里的“先乘除后加减”只是四则运算的约定,而C语言里运算符有几十种,优先级等级有15层左右,每层还有结合性。
举个例子:a = b << 2 + 1 按数学直觉应该是 (b << 2) + 1,但C语言里移位运算符的优先级比加法低,所以实际解析为 b << (2 + 1)。这哪是数学规则?这就是纯语法规定。如果你不理解这一点,就会写出自以为正确但运行结果完全不对的代码。
另外,优先级表的“高”意味着更紧密地绑定操作数。比如 *p++,后缀 ++ 优先级高于解引用 *,所以实际是 *(p++),先取 p 指向的值,再把 p 后移。换成 (*p)++ 就是先把指针指向的值取出来再加一。同样是两个字符,语义完全不同。C语言的这种“紧绑定”思想贯穿整个优先级表,理解了它,很多表达式就不需要死记。
1.2 结合性:优先级之外的另一只靴子
优先级解决的是“谁先算”的问题,但同一优先级的运算符呢?这时候就要看结合性(associativity)。结合性分两种:从左到右,从右到左。
大多数C语言运算符是左结合的,比如加减乘除:a - b - c 等价于 (a - b) - c。但有一批运算符是右结合的,包括赋值运算符、条件运算符(三元 ?:)和单目运算符,比如 *p++ 中的 ++ 和 * 虽然是不同优先级,但单目运算符自身是右结合的,所以 - -a 等价于 -(-a),而不是 (--a)。
赋值运算符的右结合性特别容易出问题。a = b = c 等价于 a = (b = c),先把 c 赋值给 b,再把赋值表达式的值(也就是赋完后的 b)赋值给 a。这是链式赋值的基础。如果你不理解右结合性,很容易误以为 a = b = c 是 (a = b) = c,后者在C语言里根本编译不过去(除非 a 是个左值并且能继续被赋值)。
结合性还有一个坑:复合赋值运算符,比如 +=、<<=、&=。它们的优先级和普通赋值一样低,也是右结合。所以 a += b += c 解析为 a += (b += c),先算 b += c,再算 a += b。这个顺序在多数情况下对结果影响不大,但如果表达式里有副作用(比如 a += GetValue()),就必须明确求值顺序。
优先级和结合性是同时作用的。判断一个表达式怎么解析,先看优先级找出“谁先结合”,再看同优先级的结合方向。比如 a + b * c,由于 * 优先级高于 +,所以是 a + (b * c),跟结合性没关系。a - b - c,优先级相同,结合性从左到右,所以是 (a - b) - c。a = b = c,优先级相同,结合性从右到左,所以是 a = (b = c)。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 一张表看懂C语言运算符优先级(附记忆技巧)
2.1 完整优先级表(从高到低)
每次查MSDN或者经典教材的附录,那一大张表确实吓人。我根据实际开发经验,把C语言常用运算符按优先级从高到低整理成下面这张简化表。注意这里的等级划分是为了方便记忆,和C标准附录的划分有些细节差异,但使用上完全够:
| 优先级 | 运算符 | 描述 | 结合性 |
|---|---|---|---|
| 1 | () [] -> . ++(后缀) --(后缀) |
函数调用、下标、成员访问、后缀自增自减 | 从左到右 |
| 2 | ++(前缀) --(前缀) ! ~ +(正) -(负) *(解引用) &(取地址) sizeof (类型) |
单目运算、强制类型转换 | 从右到左 |
| 3 | * / % |
乘法、除法、取余 | 从左到右 |
| 4 | + - |
加法、减法 | 从左到右 |
| 5 | << >> |
左移、右移 | 从左到右 |
| 6 | < <= > >= |
关系比较 | 从左到右 |
| 7 | == != |
相等性判断 | 从左到右 |
| 8 | & |
按位与 | 从左到右 |
| 9 | ^ |
按位异或 | 从左到右 |
| 10 | | |
按位或 | 从左到右 |
| 11 | && |
逻辑与 | 从左到右 |
| 12 | || |
逻辑或 | 从左到右 |
