[前へ]   [目次へ]   [次へ]

式の解釈(2)(C/C++)


今回は一つの式中に複数の演算子がある場合について解説します。
複数の演算子がある場合というのは、次のような場合です。

式1:n=2+3;
式2:n=2+3*4;

nは前回に引き続き int 型として定義されていることにします。
・・・というより前回の続きということにします。
つまり、以下のようなコードとして解説します。

<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
#include <stdio.h>

int main(void)
{
   
int n;//int型の変数 n を定義。
   
n=10;//nに10を代入。
   //前回がここまで。
   
n=2+3;//式1
   
n=2+3*4;//式2
   
return 0;

まず、式1の方についてです。前回と同じように各要素に通し記号を付けます。

A B C D E
n = 2 + 3


演算前の各要素は以下の通りです。
通し記号種別
Aint10変数(n)
B演算子(=)(2項、算術、優先2、結合←)
Cconst int2定数
D演算子(+)(2項、算術、優先12、結合→)
Econst int3定数

演算子が複数存在する場合は、各演算子の優先順位が高いものから実行されます。
この場合演算子B( = )の優先順位より演算子D( + )の優先順位の方が高いため、
演算子D( + )が先に処理されることになります。

+ 演算子は「加算」(2項、算術、優先12、結合→)、つまり足し算の演算子です。
この演算子は見た目どおり、左辺値と右辺値を加算した結果になります。

左辺値は基本型か、演算子関数が定義されている型(C++のみ)でなければなりません。
右辺値は左辺値と同じ型か、自動的に変換できる型か、
演算子関数が定義されている型(C++のみ)でなければなりません。
ただし、「 auto 」「 static 」「 const 」「 register 」「 volatile 」装飾は一致しなくてもOKです。

実はこの、
「右辺値は左辺値と同じ型か、自動的に変換できる型か、
   演算子関数が定義されている型(C++のみ)でなければなりません。
   ただし、「 auto 」「 static 」「 const 」「 register 」「 volatile 」装飾は一致しなくてもOKです。」
というのは、ほとんどの算術、論理演算子で共通のことです。

ただし、左オペランド、右オペランド共に変更は行われず、結果を格納した一時変数が生成されます。
この一時変数は実際に演算された時の型として生成され、
式の終了までという最も短い寿命を持ち、式が終了するとなくなってしまいます。


両オペランドは変更されないため、 const 装飾変数や定数を使うことが出来ます。
また、両オペランドの型が異なる場合は、前項の「暗黙の型変換」演算時バージョンで変換を試みます。
変換できない場合はエラーが発生します。
ただし、C言語は(整数型からポインタ型など)無茶な変換をするケースがあります。
C++ではそのような無茶な変換は基本的に禁止されていますので、
このような無茶な変換を行うとC++では基本的にエラーになります。
加えて、無茶な変換はバグを埋め込む原因になりやすいのでC言語の場合で警告が出た場合も、よく注意してください。

また、ここで生成される一時変数は名前がないため、上の通し記号を打つときに表記ができませんので、
「 vtemp 」の後ろに番号を打った仮の名前を与えることにします。
[注]あくまで解説用であり実際にはこの名前を使って一時変数を示すことはできないので注意してください。


さて、演算子D( + )は二項演算子なので、左辺値に定数C(2)、右辺値に定数E(3)を取ります。
そして、 2+3 の結果である5を格納した一時変数を作成し、終了します。

演算後の式は以下のようになります。

A B C
n = vtemp1


各要素は以下の通りです。
通し記号種別
Aint10変数(n)
B演算子(=)(2項、算術、優先2、結合←)
Cint5一時変数
ここで一時変数Cに const がないのに気付くと思います。
これは一時変数には上の演算時に一致しなくても良い装飾はついていかないからです。
例えば一時変数に static 装飾がついていつまでも残ってたら困りますしねぇ(笑)

まだ演算子があるので、式の処理は続行されます。

次は演算子B( = )の番ですが、右辺値の右オペランドは(一時)変数です。
算術演算子の右辺値は、変数の場合はそれが保持する値として扱われます。
この場合は5とみなして処理され、演算終了後、変数A(n)は5になります。

この結果、演算後の式は以下のようになります。

A
n


各要素は以下の通りです。
通し記号種別
Aint&5一時変数(参照先:n)
前回とほぼ同じなので解説は省略します。

ここで式に演算子がなくなったので処理が終了します。


続いて、式2の場合です。

A B C D E F G
n = 2 + 3 * 4


各要素は以下の通りです。
通し記号種別
Aint5変数(n)
B演算子(=)(2項、算術、優先2、結合←)
Cconst int2定数
D演算子(+)(2項、算術、優先12、結合→)
Econst int3定数
F演算子(*)(2項、算術、優先13、結合→)
Gconst int4定数

今回も式1同様、演算子が複数あるので優先順位で演算順序を決定します。
優先順位順で比較した結果、今回は演算子F( * )からになります。

* 演算子は、「乗算」(2項、算術、優先13、結合→)、つまり掛け算の演算子です。
さきほどの + 演算子との違いは足し算か掛け算かということだけで、他は完全に同じ動作の演算子です。

数学では 2+3*4 は 3*4 を先に処理するため、結果は14になります。
プログラムでも同じように処理できるように、 * 演算子は微妙に + 演算子より優先順位が高くなっています。

演算子F( * )は左辺値に定数E(3)、右辺値に定数G(4)を取るため、
結果は12、 + 演算子同様に一時変数が生成されます。

演算後、式は以下のようになります。

A B C D E
n = 2 + vtemp1


各要素は以下の通りです。
通し記号種別
Aint5変数(n)
B演算子(=)(2項、算術、優先2、結合←)
Cconst int2定数
D演算子(+)(2項、算術、優先12、結合→)
Eint12一時変数

さらに優先順位による比較を行い、次は演算子D( + )です。
左辺値は定数C(2)、右辺値は一時変数E(12)で、結果が14。

演算後、式は以下のようになります。

A B C
n = vtemp2


各要素は以下の通りです。
通し記号種別
Aint5変数(n)
B演算子(=)(2項、算術、優先2、結合←)
Cint14一時変数

最後に演算子B( = )を処理して変数 n が14になって・・・後は省略します。

式の解釈についてはまだまだありますが、
現状では全て解説するのは難しいのと、非常に長くなってしまうので、
式の解釈については一時休止し、次回は配列についての予定です。


[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2008/10/17