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