サンプルプログラムSample1.cでは、求めた和を変数に入れる(代入する)ために=演算子を使いました。
代入演算子には = 以外にもいくつかの種類があります。これらは加減演算子や乗除演算子、シフト演算子、論理演算子の後ろに = が付く形をしています。この形の演算子では、前に付いている演算子で左オペランドと右オペランドを計算し、その結果を左オペランドに入れます。
例えば「a += 3」では、aと3の和を求め、その結果を変数aに入れます。計算前の時点でaが5であったなら、この計算のあとにaは8(5+3の計算結果)になります。
「a += 3」という式と、「a = a + 3」という式は、基本的に同じ結果になります。しかしながら、通常は前者の書き方が優れています。後者はaを2回書かなければいけません。ここではaという短い変数名でしたが、長い変数名を何度も書くのは大変ですし、スペルミスがあると見つけるのも大変です。+=や-=が使えるところでは、迷わずこれらの演算子を使って下さい。
sum = sum + 1; printf("sum : %d\n", sum); sum += 1; printf("sum : %d\n", sum);
sum : 251 sum : 252
ところで、代入演算子を使って値を変数に入れるには、いくつかの例外を除いて変数と値の型が一致していなければなりません。一致していないときには右オペランドが左オペランドの型に変換されます。変換の詳細については、次回説明します。
増分演算子は加算演算子が2つつながった ++ という形をしていて、減分演算子は減算演算子が2つつながった -- という形をしています。
これらの演算子は1つのオペランドしかとりません。増分演算子はオペランドに1を加え、減分演算子はオペランドに1を減じた値を、そのオペランドに代入します。演算子をオペランドの前に置くか、後に置くかによって違いがありますが、それについては、次回説明します。この時点では、増分演算子、減分演算子という演算子があることを覚えてください。
増分する、つまり1を加えることをインクリメント(increment)、減分する、つまり1を減じることをデクリメント(decrement)ということがあります。この表現は、よく使われますので覚えておくと良いでしょう。
sum++; printf("sum : %d\n", sum); ++sum; printf("sum : %d\n", sum); sum--; printf("sum : %d\n", sum);
sum : 253 sum : 254 sum : 253
単項演算子には、+、-、~、!という4つの演算子があります。これらは左オペランドがなく、右オペランドだけをとります。単項とは、片方の辺のみを持つということで、つまりオペランドを1つだけとります。
単項+演算子と単項-演算子は、オペランドの符号を表します。+ はオペランドの符号はそのまま、- はオペランドの符号を反転させます。
~演算子は、ビット単位の補数を計算します。ある値の補数を計算すると、ビットが反転します。つまり、ビットの値が0ならば1になり、1ならば0になります。
単項+演算子、単項-演算子、~演算子は、整数拡張が行われます。整数拡張について詳細は次回に説明しますが、例えばchar型の値に対してこれらの演算子を適用するとint型に変換されてから計算されます。次のコードを実行してみましょう。
#include <stdio.h> #include <stdlib.h> int main(void) { unsigned char c; c = 0x5A; printf("~c : %X\n", ~c); return EXIT_SUCCESS; }
~c : FFFFFFA5
printfで始まる行では、~cの計算結果を16進数で表示しています。~cでは、まず変数cがint型に整数拡張されます。値は16進数の5Aのままですが、型はint型になりましたので、intが32ビットの大きさを持つ環境では32ビット分の大きさを持ちます。つまり、すべてのビットについて書けば0x0000005Aになります。次にその補数が計算されます。すべてのビットを反転しますので、結果は0xFFFFFFA5になります。
!演算子は、論理否定演算子とも呼ばれます。オペランドの値が0と等しければ結果は1になり、オペランドの値が0以外ならば結果は0になります。
算数では、足し算よりもかけ算を先に計算します。「1+2×3+4」は、2×3を先に計算してから足し算を計算しますので、結果は11になります。これと同じように、Cの演算子においても、+演算子より*演算子が先に計算されます。「1 + 2 * 3 + 4」と書けば、やはり結果は11になります。
ほかの演算子も同じように、同じ式の中に現れたときにどの順で処理されていくかが決まっています。この優先順位は、先に挙げた演算子の表の上のものが高く、下のものが低くなります。
演算子の表を見ると、乗除演算子は、加減演算子よりも上にあります。そのため、*演算子は、+演算子よりも先に計算されるわけです。=演算子はそれらよりも下にありますから「x = 1 + 2 * 3 + 4」という式においては、*演算子、+演算子、=演算子の順で処理されます。
ほとんどの演算子については、この優先順位は直感的に受け入れられるのではないかと思います。つまり、演算子の表を暗記しなくても、ほとんどのケースでは問題にならずにプログラミングすることができるということです。
もしプログラムを書いていく上で演算の優先順を明確にしたいときには、カッコを付けることで指定することができます。「1 + 2 * (3 + 4)」と書くと、カッコ内の3 + 4が先に計算され、計算結果は15になります。これも算数と同じですから、直感的に扱えるでしょう。
実際のところ、この演算子の優先順位表は完全なものではありません。Cの文法はもう少し複雑に定義されているため、単純に優先順位表で表すことが難しいからです。ただし、その複雑な部分は、プログラマがより直感的にCを使えるようにするためなので、心配する必要はありません。
演算子の優先順位は、短いプログラムであっても避けて通れないテーマですので、プログラムを読んだり書いたりしているうちに自然と覚えていくことでしょう。初めのうちは必要な部分だけ覚えておけばたいてい問題ないのです。
演算子はCプログラムにおける基本的な構成要素です。ほとんどの演算子は算数や数学の規則に準じていますから、直感的に動作することが分かると思います。
しかしながら、直感的に扱えるように思える演算子であっても、型を意識せずにプログラムを書いてしまうと想定していない動作をすることがあります。次回は演算子と型の関係について、今回説明しきれなかった部分をもう少し掘り下げます。
Copyright © ITmedia, Inc. All Rights Reserved.