H8+C言語入門:第4章 何もしない(3):式−演算子−
第4章の式について、補足をします。
式は、変数や定数を組み合わせたものです。
数学や算数の式と同じです。
そこでは演算子を使って、変数や定数を組合せて式を組み上げます。
式の基本要素である演算子について、そして、その組合せにおける処理の優先度について
説明しましょう。
・算術演算子
・代入演算子
・単項演算子:~(チルダ)
・前置演算子、後置演算子
・ビットごとの論理演算子
・条件式:三項演算子
・切り捨て、計算の符号
・優先度
■算術演算子
難しい日本語単語の様に思いますが、特に難しくもありません。
四則演算と知っていますよね。
そう、加算、減算、乗算(掛け算)、除算(割り算)というものですよ。
記号で表すと、そう大変身近なものであることをご存じです。
+ 加算
− 減算
× 乗算(掛け算)
÷ 除算(割り算)
これをC言語のプログラミングができる様に記号化したものが、「算術演算子」という
ものです。これを特別に「二項算術演算子」ともいいます。二つの値、変数の計算をさ
せるものです。
算術演算子 算数で使う記号
+ +
- −
* ×
/ ÷
% (なし)
一番最後に「%」があります。
これは、モジュロ演算子というものです(BASICでは、mod というような表現で使われ
ていますよね)。整数の割り算では、小数部分は切り捨てられます。
x % y
上記の式は、xをyで割った余りで、xがyでちょうど割りきれるなら0となる。
整数の時にだけ、使います。型がfloatやdoubleでは使えません。
■代入演算子
次の様な左辺が右辺に再び現れる式がある時、
i = i + 2;
次の様な圧縮した形に書くことができます。
i += 2;
上記の例では、加算+を使いました。
この代入演算子として使える算術演算子、ビット毎の論理演算子は次の通りです。
+ - * / % << >> & ^ |
!ビット毎の論理演算子については、後述しています。参照ください。
代入演算子は、その処理順序に理解を深めておく必要があります。
左辺を式leftとし、右辺をrightとして、演算子をop(operator)とした時、代入演算子の
一般形式は次の様に表現することができます。
left op= right;
で、これは、先に倣い次の様に変形することができます。
left = (left) op (right);
で、ここで要注意な点は、rightを括っている()です。
実際の式で見てみましょう。
x *= y + 1;
これは、前述の一般形式に当てはめて、
x = x * ( y + 1); であって、
x = x * y + 1; ではありません。
結構、陥りやすい見誤りをするところなので、注意ですぞ!
■単項演算子:~(チルダ)
単項演算子とは、1の補数を計算するものです。
数値の各ビットの1を0に、0を1にします。
次の様に使います。
例 ~0x55
16進数表記の0x55を0と1の表記としてみます。
0x55 → 01010101
~を付けて、0と1を反転する。
~0x55 →10101010
16進数表記で結果を表すと、0xaaとなります。
勿論変数にもこの単項演算子は使えます。次の様に使います。
例 ~i
■前置演算子、後置演算子
インクレメントとデクレメントというものがあります。
インクレメントは、++と表し、被演算数に1加え、
デクレメントは、--と表し、被演算数から1を引きます。
被演算数、つまり変数との組合せで次の様に使います。
i++; //(1)
++i; //(2)
(1)の様に演算子が後ろにあるものを、後置演算子といいます。
書き換えると i = i + 1 となります。
(2)の様に演算しが前にあるものを、前置演算子といいます。
書き換えると i = i - 1 となります。
後置演算子、前置演算子の働きは、その結果を変数に代入する時に、理解し易くなりま
す。
例えば、変数jに代入する式として、前記(1)と(2)を書き直してみます。
j = i++; //(3)
j = ++i; //(4)
iの初期値を10とした時、
(3)では、jに10を代入した後、iがインクレメントされます。
jは、10になります。
(4)では、jにiのインクレメントした後に代入します。
jは、11になります。
また、(1)と(2)の文の実行結果は?
そうです。同じです。iの値がインクレメントされた値になります。
■ビットごとの論理演算子
C言語は、次の様なビット処理用演算子を用意しています。
H8のような制御系のプログラミングでは、よく使いますのでしっかり覚えましょう。
これらは、signedでも、unsignedでもよいのですが、char、short、int及びlongの整
数被演算数にのみ使うことができます。
& →ビット毎のAND(論理積)
| →ビット毎のOR(論理和)
^ →ビット毎の排他的OR
<< →左シフト(シフト演算子)
>> →右シフト(シフト演算子)
~ →1の補数:(チルダ:単項演算子)
単項演算子は、前述しているので、使い方はそこを参照してください。
前記論理演算子の中で、排他的OR演算子というものがありました。この説明を少しし
ます。
ビット毎の排他的OR演算子では、対応するビットが異なる時には、そのビットが1とな
り、同じであるビットは、0にセットされます。
つまり、0x03と0x03の排他的ORの計算結果は、0になります。
0x03 ^ 0x03 →結果は、0
そして、0x03と0x01との排他的ORの計算結果は、次の様になります。
0x03 ^ 0x01 →結果は、0x02
0x03は、0と1(ビット)で表すと 00000011
0x01も、0と1(ビット)で表すと 00000001
排他的ORの結果、ビットが同じであれば0、異なれば1となりますから、その結果を
ビットで表すと、00000010 となります。16進数表記では、0x02となります。
シフト演算子<<と>>は左被演算数を右被演算数で指定したビット数だけシフトするの
に使われます。
x << 2 →xを左へ2ビットシフトします。
x >> 2 →xを右へ2ビットシフトします。
シフトをする時、空になるビットには0が入ります。
符号なし数の右シフトでは、左から0が入ります。
左シフトでは、右から0が入ります。
符号付き数の右シフトでは、CPUによって符号桁が左から入ってくる場合(算術シフ
ト)と、0が入ってくる場合(論理シフト)と、二通りがあります。これは、対象CPUの
取扱説明書やC言語コンパイラの同様な説明書を調べる必要があります。左シフトに
ついても同じ様です。
ここで注意すべきことがあります。
また、論理演算子に&&と||があります。&&と&とは違います。また、同様に||と|は違い
ます。
■条件式:三項演算子 ?:
これ、結構面白い式です。三項演算子?:というものを使うのですけどね。
ええ?こんな書き方ができるんだってね。
では、例を使って説明していきましょう。
次のif文、そんな面倒なものではありませんよね。
aとbを比較し、最大値zを求めるものです。
if( a > b )
z = a;
else
z = b;
これを三項演算子を使って書き直すと、次の様になります。
z = ( a > b ) ? a : b;
どう、C言語ってすごいでしょ。
■切り捨て、計算の符号
割り算/に対する切り捨ての方向、及びモジュロ演算子%に対する結果の符号は、負の
被演算数に対しては機種(CPU)に依存する。オーバーフローやアンダーフローの扱いも
同じです。
■優先度
演算子は、計算の優先度を持ちます。
+と-は、同じ優先度を持つが、
それは、同じ優先度の*、/、%よりも低い。
更に、後者は単項演算子や+や-より低い。
算術演算子は、左から右へまとめられて評価される。
優先度を次の様にまとめてみました。
同一行の演算子は、同じ優先度をもっています。
結合規則は、各行頭に記載しています。
優先度は、上から下へ向かって、減少する順となっています。
例えば、*、/、%は全て同じ優先度を持っていて、二項演算子の+と-よりも高いことを
示しています。
()演算子は、関数呼び出しを表します。
左→右) ()
右→左) ~ ++ -- + - * & (type)
左→右) * / %
左→右) + -
左→右) << >>
左→右) < <= > >=
左→右) == !=
左→右) &
左→右) ^
左→右) |
左→右) &&
左→右) ||
右→左) ?:
右→左) = += -= *= /= %= &= ^= |= <<= >>=
論理演算子の==と!=が結構上にあります。ビットのテスト(評価)を行う際、正しい結果
を得るには、括弧()を使って式を括り、計算処理の順序に気を遣う必要があります。
この中には、まだ説明していないけれど、使うものを上げておりますし、この他にも、
もう少し、C言語の演算子があります。それは、みなさんで調べてみてください。