C 语言运算符优先级
优先级 | 运算符 | 描述 | 结合性 |
---|---|---|---|
1 | ++ -- | 后缀自增与自减 | 从左到右 |
() | 函数调用 | ||
[] | 数组下标 | ||
. | 结构体与联合体成员访问 | ||
-> | 结构体与联合体成员通过指针访问 | ||
(type){list} | 复合字面量(C99) | ||
2 | ++ -- | 前缀自增与自减 | 从右到左 |
+ - | 一元加与减 | ||
! ~ | 逻辑非、逐位取反 | ||
(type) | 类型转换 | ||
* | 解引用 | ||
& | 取地址 | ||
sizeof | 取大小 | ||
_Alignof | 对其要求(C11) | ||
3 | * / % | 乘法、除法、求余 | 从左到右 |
4 | + - | 加法、减法 | |
5 | << >> | 左移、右移 | |
6 | < <= | 小于、小于等于 | |
> >= | 大于、大于等于 | ||
7 | == != | 等于、不等于 | |
8 | & | 逐位与 | |
9 | ^ | 逐位异或 | |
10 | | | 逐位或 | |
11 | && | 逻辑与 | |
12 | || | 逻辑或 | |
13 | ? : | 三元条件 | 从右到左 |
14 | = | 简单赋值 | |
+= -= | 以和赋值、以差赋值 | ||
*= /= %= | 以积、商及余数赋值 | ||
<<= >>= | 以逐位左移及右移赋值 | ||
&= ^= |= | 以逐位与、异或及或赋值 | ||
15 | , | 逗号 | 从左到右 |
如何理解优先级
分析表达式时,操作数首先与较高优先级的运算符结合(如同用括号)。例如,表达式 *p++
,因为后缀自增++
比解引用*
的优先级高,所以p
先和++
结合,所以被分析为 *(p++)
,而非 (*p)++
。
如何理解结合性
当运算符具有相同优先级时,操作数按照结合性来结合。例如表达式 a = b = c
,b 的两侧都是=
,优先级相同,但是=
的结合性是从右到左,即右边的优先,所以 b 优先与右边的=
结合,所以被分析为 a = (b = c)
而非(a = b) = c
。
几点注意
- 优先级或者结合性与求值顺序是独立的。
例如:表达式 f1() + f2() + f3()
被分析成 (f1() + f2()) + f3()
,因为 +
的结合性从左到右。但运行时对 f3
的函数调用可以最先、最后,或在 f1()
与 f2()
之间求值,同理, f1()
与 f2()
各自的求值顺序也不一定。
-
C 语言标准不指定运算符优先级。它指定语言文法,而优先级表格从它导出,以简化理解。
-
结合性规定对于一元运算符是冗余的,且只为完备而显示:一元前缀运算符始终从右到左结合(例如
++*p
为++(*p)
);而一元后缀运算符始终从左到右结合( 例如a[1][2]++
为((a[1])[2])++
)。 -
结合性对成员访问运算符有意义:
a.b++
分析为(a.b)++
而非a.(b++)
。 -
sizeof
的操作数不能是类型转型:表达式sizeof (int) * p
无歧义地转译成(sizeof(int)) * p
,而非sizeof((int)*p)
。 -
条件运算符中部(
?
与:
之间)的表达式分析为如同加括号:忽略其相对于?:
的优先级。
参考资料
https://zh.cppreference.com/w/c/language/operator_precedence