優先順位と評価順序
C 演算子の優先順位と結合規則は、式のオペランドのグループ化と評価に影響します。 演算子の優先順位は、他に優先順位が高いまたは低い演算子がある場合にだけ有効です。 優先順位の高い演算子を含む式が最初に評価されます。 優先順位は、"バインド" という言葉で説明することもできます。 優先順位の高い演算子は、より強力なバインドを持つと考えられます。
次の表は、C 演算子の優先順位と結合規則 (オペランドが評価される順序) をまとめたものです。演算子は優先順位の高い順に並べられています。 いくつかの演算子を並べて挙げている場合、その優先順位は同じであり、結合規則に従って評価されます。 表の演算子については「後置演算子」以降のセクションで説明します。 このセクションの残りの部分では、優先順位と結合規則に関する一般情報を提供します。
C 演算子の優先順位と結合規則
シンボル (1) |
操作の種類 |
結合規則 |
---|---|---|
[ ] ( ) . –> 後置 ++ および後置 –– |
式 |
左から右 |
前置 ++ および前置 –– sizeof & * + – ~ ! |
単項 |
右から左 |
型キャスト |
単項 |
右から左 |
* / % |
乗法 |
左から右 |
+ – |
加法 |
左から右 |
<< >> |
ビットごとのシフト |
左から右 |
< > <= >= |
関係 |
左から右 |
== != |
等価比較 |
左から右 |
& |
ビットごとの AND |
左から右 |
^ |
ビットごとの排他的 OR |
左から右 |
| |
ビットごとの包括的 OR |
左から右 |
&& |
論理 AND |
左から右 |
|| |
論理 OR |
左から右 |
? : |
条件式 |
右から左 |
= *= /= %= += –= <<= >>=&= ^= |= |
単純代入と複合代入 (2) |
右から左 |
, |
順次評価 |
左から右 |
1. 演算子は優先順位が高いものから順に挙げられています。 複数の演算子が同じ行またはグループ内にある場合、それらの演算子の優先順位は同じです。
2. すべての単純代入演算子と複合代入演算子は優先順位が同じです。
式には、優先順位の同じ演算子を複数含めることができます。 このような複数の演算子が式の同じレベルにある場合、評価は演算子の結合規則に従って、右から左または左から右に行われます。 評価の方向は、同じレベルで複数の乗算 (*)、加算 (+)、またはバイナリ ビット処理 (& | ^) 演算子を含む式の結果には影響しません。 演算の順序は、言語によって定義されていません。 コンパイラは、一貫性のある結果を保証できる場合には、このような式を任意の順序で自由に評価します。
順次評価 (,)、論理 AND (&&)、論理 OR (||)、条件式 (? :)、および関数呼び出し演算子だけがシーケンス ポイントを構成するため、オペランドの特定の評価順序が保証されます。 関数呼び出し演算子は、1 組のかっことそれに続く関数識別子です。 順次評価演算子 (,) は、そのオペランドが左から右に評価されることが保証されています (関数呼び出しのコンマ演算子は、順次評価演算子と同じではなく、そのような保証はないことに注意してください)。 詳細については、「シーケンス ポイント」を参照してください。
論理演算子も、オペランドを左から右に評価することを保証します。 ただし、式の結果を決定するために必要な最小数のオペランドを評価します。 これは、"ショートサーキット" 評価と呼ばれます。 したがって、式の一部のオペランドは評価されない場合があります。 たとえば、次の式では、
x && y++
2 番目のオペランド 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 演算の 1 番目のオペランドを形成します。
2 番目の式では、論理 OR 演算子 (||) は、単純代入演算子 (=) より優先順位が高いため、b || c は代入の右側のオペランドとしてグループ化されます。 a に代入される値は 0 か 1 のいずれかであることに注意してください。
3 番目の式は、予期しない結果が生じる可能性がある正しい形式の式を示します。 論理 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 がオペランドとしてグループ化されます。 条件式演算子 (? :) は、2 番目の優先順位になります。 その最初のオペランドは p == 0 であり、2 番目のオペランドは p += 1 です。 ただし、条件式演算子の最後のオペランドは p += 2 ではなく p と見なされます。この p は、複合代入演算子よりも、条件式演算子に厳密にバインドされるためです。 += 2 に左オペランドがないため、構文エラーが発生します。 この種のエラーを防ぎ、読みやすいコードを記述するには、かっこを使用してください。 たとえば、次に示すようにかっこを使用して前の例を修正すると、式を明確にできます。
( p == 0 ) ? ( p += 1 ) : ( p += 2 )