上節《編程語法分析之從表達式說起》中說到表達式,他的主要作用就是返回一個值!那這個值具體是多少,就要看表達式的整個運算過程。要理解表達式的運算過程就必須了解“優先級”和“結合律”。
之前講到表達式,一般有操作數和操作符(或者叫做運算符)組成。“優先級”和“結合律”都是針對操作數和操作符來分析的。現在就來看張表:
這張表介紹了“優先級”和“結合律”,優先級數字越小,優先級越高。在優先級相同的情況下,才會考慮“結合律”!
注意上表中,結合方向一欄,右到左的意思就是右結合,左到右,就是左結合。簡單說,“結合律”就僅僅分為“左結合”與“右結合”!
為了很好的理解“優先級”和“結合律”我舉幾個有意義的例子。
例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));