上节《编程语法分析之从表达式说起》中说到表达式,他的主要作用就是返回一个值!那这个值具体是多少,就要看表达式的整个运算过程。要理解表达式的运算过程就必须了解“优先级”和“结合律”。
之前讲到表达式,一般有操作数和操作符(或者叫做运算符)组成。“优先级”和“结合律”都是针对操作数和操作符来分析的。现在就来看张表:
这张表介绍了“优先级”和“结合律”,优先级数字越小,优先级越高。在优先级相同的情况下,才会考虑“结合律”!
注意上表中,结合方向一栏,右到左的意思就是右结合,左到右,就是左结合。简单说,“结合律”就仅仅分为“左结合”与“右结合”!
为了很好的理解“优先级”和“结合律”我举几个有意义的例子。
例1、这个例子主要从“结合律”出发,讨论左结合与右结合的特点。
所谓结合,就是多个东西结合成为一个整体,而成为一个新的东西。当一个操作符是一个左结合且为双目运算符时,他会把他左边的东西整个当作一个整体并与之结合,右边的只认离他最近的一个。(右结合与之相反)
如:(这是一个C++例子,能很好的理解结合这个概念)
对于第二个<<运算符而言,他会把他左边的全部当中一个整体,及把当作一个整体,这个整体其实就是个表达式,他是一个值,他的值就是std::cout的值。
而对于第一个<<运算符而言,在他的右边他只认“Hello,World!”及右边的只认离他最近的一个。
在原文<Accelerated C++>中是这么解释的;
如果您多C++不熟悉,我们就来看第二例子:
例2、一个超级简单的表达式,此时你应该有更深的认识:
a + b + c
首先,此表达式中,操作符都是加号,大家优先级相同,所以转而考虑结合性,+是左结合。
所以第一个加号先与a结合,并且只认右边和他最近的b,而对于第二个加号,会把a+b当作一个整体,并与之结合,然后只认右边和他最近的c。结果就是((a) + b) + c 。
如果前两个例子都不过瘾,我们来看第三个例子:
例3、这个例子需要兼而考虑优先级”和“结合律”。
(* ( ( void (*)() )0 ) )()
这里操作符有小括弧——强制转换符(形式上也是小括弧),解引用符,操作数只有一个,就是0;操作符都是针对操作数的。
我们先从0开始看,和0最近的是小括弧,这个小括弧里面是个void (*)()这其实是个类型——函数指针类型,用小括弧把类型括起来,这个小括弧其实是强制转换符。那么( void (*)() )0 这个表达式结合起来,就表示把0,强制转换为函数指针类型。
在往外又是一个小括弧,这个小括弧就是说小括弧内部是一个结合的整体。此时由于( void (*)() )0是一个整体而且表示一个函数指针,所以把( void (*)() )0替换为p,结果就是(* p )(),这句话的意思其实就是利用函数指针p调用函数。而这p其实是指向地址0的。所以这句表达式的副作用就是,让程序指针PC跳到地址0,及完成一个软件复位的功能。
进一步讨论如果,去掉其中的一层括号:
(* ( void (*)() )0 )()
那么一开始有两个操作符针对操作数0,一个是强制转换符(类型),一个是解引用*观察上表可知(类型)和 * 的优先级都是2,优先级相同,而结合性是右结合,简化一下表达式再分析:
(* ( 类型 )0 )()
因为是右结合,所以*会把右边的( 类型 )0当作一个整体,及 ( 类型 )先和0结合,所以结论是去掉这层括号含义不变!
趁热打铁,我们来看第四个例子:
例4、ph->pNext->pNext->pNext->pNext->pNext
这种表达式通常是在链表的访问中见到,别看他这么长其实也就返回是一个值,所以不必怕它。
ph是个头指针,->这个符号查表得知是左结合,及左边的看成整体,右边的只认一个那么ph->pNext就可以被单独分离出来并且结合到一起成为一个整体,
ph->pNext看成整体之后,其实就是返回一个指针,及第0个节点中存放的指针值!而这个指针指向第1个节点。所以ph->pNext可以用p1代替。
剩下的p1->pNext->pNext->pNext->pNext,依照上面的方法如法炮制就得到p2->pNext->pNext->pNext。最终就得到p4->pNext.
如果说ph指向第0个节点,p4->pNext最终的结果其实就是第4个节点中存放的指针值,指针指向第5个节点。这也就是整个表达式的结果。
最后一个例子引入,逗号表达式作为饭后甜点。
例5、逗号表达式
逗号表达式形如:表达式1,表达式2
首先,逗号表达式,也是个表达式,逗号表达式作为整体也返回一个值!
其次,整个逗号表达式的结果为表达式2的结果。
可能有的同学要发问了,那表达式1不是个打酱油的?其实,表达式1一般是为表达式2做个铺垫,如:(从MFC截取的一个例子)
表达式1其实是给str赋值,表达式2就是一个比较语句,那么if只会判断表达式2的结果是否为真,而不会理会表达式1的返回值。
在使用逗号表达式时,一定要注意优先级的问题,因为“,”的优先级比“=”的优先级还要低。
例如:a = 3*5 , a*4; 由于“,”的优先级比“=”的优先级低,所以a = 3*5先结合,算出a等于15,然后a*4得到60.再根据“整个逗号表达式的结果为表达式2的结果”
所以整个表达式(a = 3*5 , a*4)的结果是60.
具体测试方法为:
int a;
printf("%d",(a = 3*5 , a*4));