1. 優先級運算符的使用
我相信玩過C的人都曾有過這樣的或那樣的不可思議經歷,會非常感慨C的博大精深、深不可測,很多時候你根本不知道一條語句的真實執行情況(除非經過具體環境的編譯和執行得出結論,可能你事後還是很迷茫),其實,有些已成事實特性並不是原本設計C語言時想要看到的,因為有些運算符的優先級是錯誤的,如果你不相信,下面就來看一下這樣例子:
i = 1, 2;
你覺得i的結果會是多少?我們知道逗號的運算符的值就是最右邊操作數的值。但在這裡賦值符的優先級更高,所以實際情況應該是:
(i = 1), 2; /* i的值為1 */
i負值為1,然後執行常量2的運算,計算結果丟棄。最終i的結果是1而不是2。
2.常見的最容易犯錯的優先級運算符
1)"."的優先級高於"*"
舉例:*p.f
可能誤以為的結果:p所指對象的字段f,(*p).f
實際結果:對p取f偏移,作為指針,然後進行解除引用的操作 *(p.f)
2) "[]"的優先級高於"*"
舉例:int *ap[]
可能誤以為的結果:ap是一個指向int數組的指針 int(*ap)[]
實際結果:ap是一個元素為int指針的數組 int *(ap[])
3) 函數"()"的優先級高於"*"
舉例:int *fp()
可能誤以為的結果:fp是一個函數指針,所指函數返回int,int (*fp)()
實際結果:fp是一個函數,返回類型int *,int *(fp())
4) "=="和"!="的優先級高於位操作符
舉例:(val & mask != 0)
可能誤以為的結果:(val & mask) != 0
實際結果:val & (mask != 0)
5) "=="和"!="的優先級高於賦值符
舉例:c = getchar() != EOF
可能誤以為的結果:(c = getchar()) != EOF
實際結果:c = (getchar() != EOF)
6) 算術運算符優先級高於移位運算符
舉例:msb << 4 +lsb
可能誤以為的結果:(msb << 4) +lsb
實際結果:msb << (4 +lsb)
7) 逗號運算符優先級低於所有其他運算符
舉例:i = 1, 2
可能誤以為的結果:i = (1, 2)
實際結果:(i = 1), 2
對於這些運算符的大部分,如果坐下來好好想想就能變得明了,但是像第'7)'種可能會讓很多程序員痛心疾首。所以在表達式中如果有布爾操作、算術運算、位操作等混合運算,你最好應該在適當的地方加上括號,只是清楚明了,事實證明這是一個良好的變成風格。
3. 操作符的結合性
操作符優先級用來決定不含括號的表達式中操作數之間的“緊密”程度,如果具有相同的優先級的操作符出現,那操作符的結核性就開始發揮作用了。
舉例:int a, b = 1, c = 2;
a = b = c;
對於這個實例,如果先執行"b = c",a的結果為2,如果先執行"a=b",a的結果為1。事實上所有的賦值符(包括符合賦值符)都是右結合性,因此這裡的a的結果為2。
類似地,具有左結合性的操作符是從左向右依次執行,如位操作符"&"和"|"。結合性用於表達式中兩個以上的相同的優先級的操作符的情況,事實上所有的優先級相同的操作符,他們的結合性也是相同的。
4.總結
在C語言中,跟順序有關的問題,有些定義很好,如優先級和結合性,有些定義的很含糊,如大部分表達式中的各個操作數計算順序就是不確定的,他的目的是為了讓編譯器設計者選擇最合適的方法來產生最快的代碼。但是要注意的是在函數調用中,各個參數的計算順序是不確定的。