運算子優先權 (C 語言)
Percedence Table

運算子
Operator
說 明
Description
結合順序
Associativity
1 ()
[]
->
.
++ --
Function call
Array subscripting
Element selection (of struct or union) through pointer
Element selection (of struct or union) by reference
increment/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)右至左, 二運算元及其他均為由左至右.)
  • 運算式中無括號強制指定優先權的部份, 優先權值小的運算子先執行運算, 優先權相同時則依 '結合順序' 判定. 以下是結合順序之例子:
    1. a-b+c-+ 同為優先權4, 結合順序為 '左至右' 所以是 (a-b)+c 而不是 a-(b+c)
    2. a->b.c->. 同為優先權1, 結合順序為 '左至右' 所以是 (a->b).c 而不是 a->(b.c)
    3. a=b=10 中兩個 = 優先權相同, 結合順序為 '右至左' 所以是 a= (b=10), 而 b=10 的回傳值是 10, 所以 a,b 都會被設成 10 (指定運算的回傳值為等號右邊的運算結果)
    4. a+=b-=1+=-= 同為優先權14, 結合順序為 '右至左' 所以是 a += (b-=1)
      {   b=b-1;
          a=a+b;
      }
      所以如果運算式執行前 a 值為 5, b 值為 2, 則執行後 a 值 6, 為 b 值為 1.
    5. a?b:c?d:e 中兩個 ?: 優先權相同, 結合順序為 '右至左' 所以是 a?b:(c?d:e)
    6. a+=b<<c-d<<e+= 優先權14, << 優先權5, - 優先權4, 所以是 c-d 先執行. 之後兩個 << 結合順序為 '左至右' 所以是 (b<<(c-d))<<e, 最後才是 +=
  • 註1: 請避免使用例2例4~例6這類奇怪 (又損人不利己) 或容易搞錯的寫法, 加上括號可以淢少混淆就加上吧!
  • 註2: 請避免在運算式中有多次使用某一變數, 但又同時更動該變數內容的寫法. 特別是 ++ 及 -- 運算子或者是優先權 14 的指定運算子, 要小心下面列出來的寫法不要用. 原因是某些動作 C 語言並未規範其執行的次序. (後果是換用不同的 C 編譯器可能產生不同執行次序的執行碼, 進而在執行時產生不同結果, 迫使移值人員必需仔細測試並追查原因, 而增加整個移植計畫的時程)
    // 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

    MagicJackTing 發表在 痞客邦 留言(3) 人氣()