式とは? そして演算子の処理順番

式とは?

式の英単語はexpressionです。 式と言うと、数学的イメージがありますが、英単語のexpressionの直訳では、 「表現すること」と訳されます。
そして、プログラミングの世界では、データを表現することになります。

データを表現する箇所は、if() や、while()、 printf("%d" ,) などとさまざまです。

つまりデータを表現できるものは何でも式になります。つまり、
定数の単体の表現や、
変数の単体の表現や、
戻り値がある関数呼び出しの表現、
そしてこれらを演算子で組み合わせた表現!
 これらすべては、データ表現しているので、式といえます。
(そして、式は ; のセミコロンを付けることで、 単純文というifやwhileなどで制御可能な実行の単位になります。)

 

演算子の処理順番(優先順位と結合規則)

演算子で構成した式は、プログラマが指示できる最も小さい処理単位です。
そして、使うと使わずに関わらず、データを表現しているというわけです。
複数の演算子で、式を構成する場合、 ひとつ演算子で得られる結果のデータが、次の演算子の処理対象になります。 (この演算対象は、演算子のオペランドと呼ばれます。)
そうやって、 ひとつずつ演算が行われて、最終的に全体の処理結果となるデータを指示します。
つまり演算子を使う場合は、どの演算子から処理を行わせるかを、明確に指示できなければなりません。
その実行する順番は、優先順位の高いものから行われます。 また同じ優先順の場合は結合規則で実行することになっています。 その優先順位と結合規則の表を以下に示します。
表の上の方の演算子の優先順位が高く、同じ行は同じ優先順位になっていて、 その時は結合規則に従って、処理順が 決ります。

以下に簡単な例を示します。例えば、
int a[5] = { 4, 2, 6 }; の配列とint n; の変数が用意されているとします。

この後の実行例で、n = a[2] - a[0] * a[1];と行うと、nに記憶されるデータは、-2になります。
ここで、使われる=演算子と、-演算子*演算子は、 左右に2つのオペランドを持つので2項演算子と呼ばれます。
ここで=-より*の方の優先順位が高いので、a[0] * a[1]が先行して8が演算結果になります。

それが、-の右項のオペランドになり、 a[2] - 8の演算が行われ、その結果のデータ-2が、最終的に=演算子でnに記憶されます。 そして=演算子の結果として、その記憶内容の-2が得られます。(ここで、このデータは使われません。)

では、n = a[2] - - a[0] * a[1];ではどうでしょうか? nに記憶されるデータは、16です。
こんどは、2番目にある-単項演算子(オペランド1つ)が、ここで掛け算より高い優先順位になります。

よって、a[0] * a[1]の前に、- a[0]が働き、-4の演算結果が得られます。
これとa[1]が、*のオペランドになり、-8が得られます。
そして、これが2演算子の - のオペランドになり、 6 - -8 の計算結果である14が得られます。 最後に=演算子でnに記憶され、その記憶内容の14=演算子の結果として得られます。(このデータは使われません。)
例えば、printf("%d", n = a[2] - - a[0] * a[1]);という実行文であれば、=演算子の結果 である14がprintfの引数で使われることになります。


単項演算子は右側がオペランドになり、右から左へ結合します。
sizeofは、オペランドが配列名の場合に配列全体のバイト数を結果にし、 オペランドが式の場合は『その式の演算結果を記憶するために必要なバイト数』を演算子としての結果にします。
よって、int型サイズが4byteの場合、n = sizeof aとすると、 上記例の配列は5個で、要素がint型なので、5掛ける4の20が演算結果として得られて、その20がnに記憶されます。

n = sizeof a[2]とすると、[]演算子が優先されて、この要素の6を記憶するに必要なint型サイズ4byteの4がnに記憶されます。

この式が、n = ! sizeof aになると、どうなるでしょうか? 
この場合は、sizeof演算子と、!演算子の優先順位は同じなので、結合規則より、右から作用して、先にsizeof aが働いて、 20の結果が得られます。それに !が働きます。!は、右の条件の論理値を反転します。つまり右が0以外(成立)なら、0の結果が得られます。 よってこの結果は0になり、nに0が記憶されます。


n = sizeof ! aはどうなるでしょうか? 
この場合は、sizeof演算子と、!演算子の優先順位は同じなので、結合規則より、右から作用して、まず ! aの結果をだします。

!は、右の条件の論理値を反転します。つまり右が0以外(成立)なら、0の結果が得られます。それはint型なので、 これをオペランドとするsizeofの演算結果は4になり、その4がnに記憶されます。