第18回
条件式と演算子~制御構造をさらに理解する

条件式の基本

論理的な『動く仕組み』をソースコードとして展開できるようになるためには、まず制御構造をしっかり理解し、その組み立て方を身に付けていただきたいと思います。その基本はifやwhileに与える条件式にあります。

比較演算と論理演算

制御構造で最も重要な部分は《条件式》です。どのような条件を与えるか──どのような状態のときに処理の流れを切り替えるのか、ということが、プログラムの柔軟性にとって最重要項目なのです。ifやforの構造が正しくても、条件を間違えてしまったら元も子もありません。

その条件式を記述するために欠かせないのが、比較演算と論理演算です。既に紹介しましたが、もう一度取り上げておきましょう。

比較演算に表1のような比較演算子を用い、2つの値の『大小関係』を調べて真(式が正しい)または偽(式が正しくない)のどちらかの結果を返します。

表1:比較演算子
演算子 機能  
== 左辺と右辺が等しい x == 10 xが10のとき真、それ以外のとき偽
> 左辺が右辺より大きい x > 10 xが11以上のとき真、10以下のとき偽
< 左辺が右辺より小さい(未満) x < 10 xが10未満のとき真、10以上のとき偽
>= 左辺が右辺より大きいか等しい(以上) x >= 10 xが10以上のとき真、9以下のとき偽
<= 左辺が右辺より小さいか等しい(以下) x <= 10 xが10以下のとき真、11以上のとき偽
!= 左辺と右辺が等しくない x != 10 xが10以外のとき真、10のとき偽

論理演算には表2のような論理演算子を用い、2つの式の『成立の仕方~関係』を調べて真(式同士の関係が正しい)または偽(式同士の関係が正しくない)のどちらかの結果を返します。

表2:論理演算子
演算子 機能
&& 左辺式と右辺式が共に真のとき真を返す~AND(論理積)
|| 左辺式等辺式のどちらか一方(または両方)が真のとき真を返す~OR(論理和)
! 続く式の反対(式が真なら偽、偽なら真)を返す~NOT(否定)

式の値と論理値

プログラミングでは、何らかの演算を行う命令文を「式」と言い、式はすべて値を伴います。例えば、変数xに数値を代入する次の式
x = 100;
は、代入される値である100という数値を伴っています。従って上の式の「値は100」ということになります。

同様に、比較演算子を使った式の演算結果も値を伴います。真(TRUE)または偽(FALSE)という2つの値のどちらかで、論理値と呼ばれます。Visual Basicなどでは、これをBoolearnという名前の論理型として扱い、True(真)とFalse(偽)という記号を割り当てていますが、Cでは式の値はint型の整数で「偽は0、真は0以外(通常は1)」としています。

例えば
x >= y
という条件式は、xの値がyの値以上なら1、そうでないときには0という値を返すことになります。ifなどの命令は、条件式値を調べて次に実行する処理を切り替えるのです。

式の値を比較する必要はない

Visual Basicでは、よく次のような式を記述します。
If (x >= y) = True Then ...

Cでも、関係演算子は「値を比較した結果が真なら1、偽なら0を返す」ようになっているため、同じように
if ((x >= y) == 1)
と書くこともできます。

しかし「真か偽か?」を調べる処理で「1と比較」すると、ソースが分かりにくくなります。以下のように、0でない状態と比べるのも同じです。
if ((x >= y) != 0)

が、Cでは条件式の値が真であるか偽であるかについてまで、わざわざ式を書いて比較しなくても構いません。単純に
if (x >= y) ...
と書けば、条件式が真の場合に続く処理を実行するよう決められています。ifやwhileでは続く( )内に条件式だけを書くのが普通です。

ただ、場合によってはVisual Basicのように、ある値(例えば自作した関数の戻り値など)が真か偽かを調べたい場合には、以下のような記号定数を定義しておくと便利です。
#define BOOL  int        /* 論理型 */
#define FALSE 0          /* 偽の定義 */
#define TRUE  !FALSE     /* 真の定義 */

「真」を1に固定してしまうと、計算結果を調べる場合や失敗時に0を返す関数の戻り値を調べる場合に、1以外の値を「TRUEではない」と判断されることがあるので、「真は0以外」と定義しておきます。

式と式の関係を調べる

条件式が複雑になると、条件式を2つ並べてそれぞれの関係を調べることになります。そのときに用いるのが論理演算子です。関係演算子とも呼ばれ、真偽を伴う2つの式の『関係』を調べる式を作ります。

次の式の(a)では「変数numが0以上」を調べ、(b)では「変数numが9以下」であるかを調べています。論理演算子&&はこの2つの式が『共に真』であるときに真となります。
if ((num >= 0) && (num <= 9))
       (a)           (b)
つまり上の式は
変数numが『0~9の間』であるかどうか
を調べていることになります。

「読める」と「作れる」は違う

ここまでのことは既に本コラムの第5回でおおよそ説明してきました。また、「式」とは値を持つものだということも、第5回のコラム「気になる専門用語」で触れました。

ここで重要なことは、上の式を見て「変数numが0~9の間であるかどうか」をわかることより、プログラムの設計時に
変数numが0~9の間であればxxxxの処理をする
という仕様に対して上のような式を書けるかどうかです。一見同じことのように思えますが、両者はまったく異なる発想を必要とします。

自動車に詳しい人なら、道路を走っている自動車を見て『あれはxxx社製のyyyというクルマだ』とわかるでしょう。しかし、『xxx社製のyyyというクルマを描け』と言われても簡単には描けません。

ソースを読めることと、現実の処理をソースにすることとは随分違うのです。それが顕著に表れるのが制御構造、とりわけ条件式の記述なのです。プログラミングに関心のある人は、とかくソースコードを読み解くことに意識が向かいがちです。しかし、現実の処理をソースコードに展開することの方が難しく、そのことの方が重要です。