引言
- 运算符 ( operator ) 作用于操作数 ( operand ),这样就生成了表达式 ( expression )
- 当没有运算符时,操作数本身也是一个表达式
- 一个表达式总有一个唯一确定的值,计算机的本质就是计算和存储表达式的值
- 那么这个值是如何计算呢
- 只由一个操作数形成的表达式,它的值自然就是操作数本身的值
- 那么由多个操作数和运算符组成的表达式,它的值又是怎么算出来的呢
- 这涉及到两个方面
- 运算符的优先级和结合性,它解决的是:某个运算符到底跟哪个操作数进行计算的问题
- 计算子表达式的先后顺序,它解决的是:形成某个表达式的多个子表达式,到底哪个先计算的问题
各个编程语言都有关于运算符的优先级和结合性的问题,特别是像 C 语言这种运算符特别多的语言,搞清楚各种运算符的优先级和结合性是一个让人头疼的问题。
写这篇文章是为了搞清楚运算符的优先级和结合性的本质。
运算符的优先级和结合性
- 同一个表达式在同一时间只能跟一个运算符进行计算,比如
a + b * c
,b
要么跟+
算,要么跟*
算 - 所以当同一个表达式左右两边各有一个运算符的时候,到底跟哪个算成了一个问题
- 当这两个运算符的优先级大小不一样的时候,优先级可以解决表达式跟谁算的问题,比如
*
的优先级比+
高,那么a + b * c
,b
就要跟*
算,那么也就是a + (b * c)
- 当这两个运算符完全一样(如
a + b + c
),或者优先级大小一样的时候(如a * b / c
), 就要靠结合性来解决表达式跟谁算的问题。比如+
是左结合的,那么a + b + c
也就是(a + b) + c
;又比如=
是右结合的,那么x = y = z
也就是x = (y = z)
- 具体每个运算符的优先级大小和结合性方式,需要看对应语言的文档,通过查表来解决
- 一个表达式总是想算出一个结果,得到一个唯一确定的值,计算过程中产生的其他效果都是副作用
计算子表达式的先后顺序
- 解决了一个表达式怎么分配运算符和操作数的问题后,剩下的事情自然就是计算了,那就有个计算的先后问题
- 对于 C 语言来说,并非优先级高的就先算,优先级低的就后算。比如
a * b + c - d
,a
,b
,c
,d
这 4 个子表达式,先算哪个是不一定的,不一定是先算a * b
, 再算+ c
, 最后算- d
- 所以这也就是为什么在 C 语言里,不能出现这种表达式:
a = (++a * b) / c
, 因为a
和++a
的计算先后顺序是未定义的,那么你在一个表达式里对同一个变量,对它同时进行改变和赋值的操作,是很危险的,程序的结果是未定义的 - 对于 JavaScript,ECMAScript 标准规定,表达式永远从左往右进行计算
网友评论