優先順序和評估順序
C 運算子的優先順序和順序關聯性會影響運算式中運算元的群組和求值。 有其他優先順序更高或更低的運算子存在時,運算子的優先順序才有意義。 具有較高優先順序運算子的運算式會先進行求值。 優先順序也可以用「繫結」(Binding) 這個詞描述。具有較高優先順序的運算子可視為具有更緊密的繫結。
下表摘要說明 C 運算子的優先順序和順序關聯性 (運算元的求值順序),並依照最高到最低的優先順序列出。 有數個運算子一起出現時,表示它們擁有相同的優先順序,並且會依其順序關聯性求值。 表中的運算子將從後置運算子開始,分成多個章節描述。 本節的其餘內容將提供關於優先順序和順序關聯性的一般資訊。
C 運算子的優先順序和順序關聯性
Symbol1 |
運算類型 |
順序關聯性 |
---|---|---|
[ ] ( ) .–> 後置 ++ 和後置 –– |
運算式 |
由左至右 |
前置 ++ 和前置 –– sizeof & * + – ~ ! |
一元 |
由右至左 |
類型轉換 |
一元 |
由右至左 |
* / % |
乘法類 (Multiplicative) |
由左至右 |
+ – |
加法類 (Additive) |
由左至右 |
<< >> |
位元移位 |
由左至右 |
< > <= >= |
關聯性 |
由左至右 |
== != |
相等 |
由左至右 |
& |
位元 AND |
由左至右 |
^ |
位元互斥 OR |
由左至右 |
| |
位元包含 OR |
由左至右 |
&& |
邏輯 AND |
由左至右 |
|| |
邏輯 OR |
由左至右 |
?: |
條件運算式 |
由右至左 |
= *= /= %= += –= <<= >>=&= ^= |= |
簡單和複合指派2 |
由右至左 |
, |
循序求值 |
由左至右 |
1. 運算子是依遞減的優先順序列出。 如果多個運算子出現在同一行或某個群組中,表示它們具有相同的優先順序。
2. 所有簡單和複合指派運算子都具有相同的優先順序。
運算式可以包含數個具有相同優先順序的運算子。 若有數個這類運算子出現在運算式中的相同層級上,則會根據運算子的順序關聯性由右至左或由左至右求值。 求值的方向不會影響相同層級上包含多個乘法 (*)、加法 (+) 或二進位位元 (& | ^) 運算子的運算式結果。 運算的順序不是由語言所定義。 如果編譯器能夠保證結果一致,則可以依任意順序求出這類運算式的值。
只有循序求值 (,)、邏輯 AND (&&)、邏輯 OR (||)、條件運算式 (?:) 和函式呼叫運算子會構成序列點,因此可確保其運算元依照特定的求值順序。 函式呼叫運算子是接在函式識別項後面的一組括號。 循序求值運算子 (,) 一定會由左至右求出運算元的值 (請注意,函式呼叫中的逗號運算子與循序求值運算子並不相同,也不會提供這類保證)。如需詳細資訊,請參閱序列點。
邏輯運算子也一定會由左至右求出運算元的值。 不過,這類運算子會判斷求出運算式結果所需的最少運算元數目。 這稱為「最少運算」(Short-circuit) 求值。 因此,運算式中不會求出某些運算元的值。 例如,運算式
x && y++
的第二個運算元 y++ 只有在 x 為 true (非零) 時才會求值。 因此,如果 x 為 false (0),y 就不會遞增。
範例
下列清單顯示編譯器如何自動繫結數個範例運算式:
運算式 |
自動繫結 |
---|---|
a & b || c |
(a & b) || c |
a = b || c |
a = (b || c) |
q && r || s-- |
(q && r) || s–– |
在第一個運算式中,位元 AND 運算子 (&) 的優先順序高於邏輯 OR 運算子 (||),因此 a & b 形成邏輯 OR 運算的第一個運算元。
在第二個運算式中,邏輯 OR 運算子 (||) 的優先順序高於簡單指派運算子 (=),因此 b || c 會分組為指派中的右方運算元。 請注意,指派至 a 的值不是 0 就是 1。
第三個運算式所顯示的運算式雖然格式正確,但是可能會產生未預期的結果。 邏輯 AND 運算子 (&&) 的優先順序高於邏輯 OR 運算子 (||),因此 q && r 會分組為一個運算元。 由於邏輯運算子一定會由左至右求出運算元的值,因此 q && r 會在 s–– 之前先求值。 不過,如果 q && r 判斷值為非零值,則不會計算 s–– 的值,而且 s 不會遞減。 如果 s 不遞減會造成您的程式發生問題,則 s–– 應該做為運算式的第一個運算元,或是在另一項運算中讓 s 遞減。
下列運算式不合法,並且會在編譯時期產生診斷訊息:
不合法的運算式 |
預設群組 |
---|---|
p == 0 ? p += 1: p += 2 |
( p == 0 ? p += 1 : p ) += 2 |
在這個運算式中,相等運算子 (==) 具有最高優先順序,因此 p == 0 會分組為一個運算元。 條件運算式運算子 (? :) 具有第二高的優先順序。 它的第一個運算元是 p == 0,而且第二個運算元是 p += 1。 不過,條件運算式運算子的最後一個運算元會視為 p,而不是 p += 2,因為出現在這裡的 p 與條件運算式運算子的繫結緊密程度高於與複合指派運算子的繫結。 由於 += 2 並沒有左方運算元,所以發生語法錯誤。 您應該使用括號來防止這類錯誤發生,並且產生更容易閱讀的程式碼。 例如,您可以依照下面所示,使用括號修正並釐清前述範例:
( p == 0 ) ? ( p += 1 ) : ( p += 2 )