運算子優先權 (C 語言) Percedence Table
運算子 Operator |
說 明 Description |
結合順序 Associativity | |
---|---|---|---|
1 | () [] -> . ++ -- |
Function call Array subscripting Element selection (of struct or union ) through pointerElement selection (of struct or union ) by referenceincrement/decrement (suffix) (註1) |
左至右(註2) |
2 | ! ~ ++ -- + - * & (type) sizeof |
logic NOT bitwise NOT increment/decrement (prefix) unary plus and minus Indirection (dereference, right value) Address-of (left value) type cast Size-of |
右至左(註2) |
3 | * / % | Arithmetic multiplication, division, and remainder | 左至右 |
4 | + - | Arithmetic addition, subtraction | 左至右 |
5 | << >> | Bitwise left shift, right shift | 左至右 |
6 | < <= > >= |
Relational less than, not greater than Relational greater than, not less than |
左至右 |
7 | == != | Relational equal, not equal | 左至右 |
8 | & | Bitwise AND | 左至右 |
9 | ^ | Bitwise XOR | 左至右 |
10 | | | Bitwise OR | 左至右 |
11 | && | Logical AND | 左至右 |
12 | || | Logical OR | 左至右 |
13 | ?: | Ternary conditional | 右至左 |
14 | = += -= *= /= %= &= ^= |= <<= >>= |
Direct assignment Assignment by sum, difference Assignment by product, quotient, remainder Assignment by bitwise AND, XOR, OR Assignment by bitwise left shift, right shift |
右至左 |
15 | , | Comma | 左至右 |
註1: 這一條和 K&R C 書上所列不同, 這是 K&R C 原版的錯誤. 目前所有的 C/C++ 編譯器都還保留這個錯誤, 並且不會被修正. 請參考 Wiki: C (programming language) Syntax 的第 5 小段 (標題 "Character Set" 的前面小段). 或者 K&R 原版 第 3 頁. 摘錄如下:
"C, like any other language, has its blemishes. Some of the operators have the wrong precedence; some parts of the syntax could be better."
註2: 其實算起來第一項, 第二項都是單一運算元之運算子 (unary). 它們並沒有所謂結合順序的問題. 二者的結合原則都是 '近端' 優先. 第一項所列都是寫在運算元右邊的, 所以有多個運算元寫在一起時自然是左邊的離運算元比較近, 所以是由 '左至右' 結合. 第二項所列都是寫在運算元左邊的, 所以右邊的離運算元比較近, 自然是由 '右至左' 結合. 那..., 下面的 '記憶口訣' 就自己更正吧.
注意事項:
- 第 2, 13, 14 的結合次序為 右至左, 和其他群組不同 (記憶口訣: 單運算元(2), 三運算元(13), 指定運算類(14)為右至左, 二運算元及其他均為由左至右.)
- 運算式中無括號強制指定優先權的部份, 優先權值小的運算子先執行運算, 優先權相同時則依 '結合順序' 判定. 以下是結合順序之例子:
- a-b+c 中 - 和 + 同為優先權4, 結合順序為 '左至右' 所以是 (a-b)+c 而不是 a-(b+c)
- a->b.c 中 -> 和 . 同為優先權1, 結合順序為 '左至右' 所以是 (a->b).c 而不是 a->(b.c)
- a=b=10 中兩個 = 優先權相同, 結合順序為 '右至左' 所以是 a= (b=10), 而 b=10 的回傳值是 10, 所以 a,b 都會被設成 10 (指定運算的回傳值為等號右邊的運算結果)
- a+=b-=1 中 += 和 -= 同為優先權14, 結合順序為 '右至左' 所以是 a += (b-=1)或
{ b=b-1; a=a+b; }
- a?b:c?d:e 中兩個 ?: 優先權相同, 結合順序為 '右至左' 所以是 a?b:(c?d:e)
- a+=b<<c-d<<e 中 += 優先權14, << 優先權5, - 優先權4, 所以是 c-d 先執行. 之後兩個 << 結合順序為 '左至右' 所以是 (b<<(c-d))<<e, 最後才是 +=
// C 未規範等號左邊 (索引) 或者右邊 (遞增) 哪一個先計算
a[i]=i++;
// C 未規範函數參數的計算次序
printf("%d %d\n", ++n, power(2, n));
執行次序
C/C++ 雖然規範了運算子的結合次序, 但大多數狀況沒有規範運算元的執行次序. 有規定的運算元計算次序的運算子只有 &&, || , ?: 和 , 等四個. 例如:
funcA() && funcB() && funcC()
上式中 funcA() 要先執行, 再來是 funcB(), 再來是 funcC(). 但如果是
funcA() + funcB() + funcC()
只會被轉譯成 (funcA() + funcB()) + funcC() 但可沒有規範 funcA(), funcB(), funcC() 三者之中哪一個需要先執行計算,哪一個後執行計算.
另外要特別注意的是 , 指的是二個 statement 以 , 串起來, 而不是呼叫函數時的參數. 例如:
for (i=0, j=0; i<len; i+=j, j+=2)
其中的 i=0, j=0 這一段 i=0 先執行, 再執行 j=0.
再來的 i+=j, j+=2這一段 i+=j 先執行, 再執行 j+=2.
有問題的寫法
以下的式子都是有問題的寫法
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
i = ++i + 1; // undefined behavior (well-defined in C++11)
++ ++i; // undefined behavior (well-defined in C++11)
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior