Version 6.12
演算子を気に掛ける!
「さて今回から、演算子関係でバグの出やすい部分や見つけ方とかを具体的
に紹介していきます」
『バグの出やすいとこってあるんだ』
「あるよー。まず重要なのは、基本型に演算子を使うって事は、関数を呼ぶ
ことじゃないってこと」
『何言ってんの、当たり前じゃん』
「まぁそれはそうなんだけど、その当たり前の事にいろんな問題があるんで
す。たとえば、書き間違い」
void CDebugDlg::OnButton1()
{
int i = 0;
if( i = 0 )
{
TRACE( "Hit!\n" );
}
}
「あ、これすんごく分かりやすいね……」
『え、何が?』
「って、気付かないの?」
『え”……………………あ! if( i == 0 ) じゃないの!?』
「そうです。これだとどうなると思う?」
『え? んー、普通 if の中で = なんて使わないし……』
「 i = 0 すると i に置き換わるから、その i が if に掛けられる、つま
り if( i ) と同じ事になるから」
『 i は 0 だから、 if の中に入らない!』
「そゆこと。で、重要なのは、 = が1個か2個かでここまで変わるってこ
と。メンバ関数ならそういうことないでしょ」
『そりゃ、関数の名前違っちゃうことになるんだからそうだね』
「演算子はシンプルだから、その分ちょっとした間違いが大きな問題になり
かねないから。それに、関数と違ってブレークポイントを付けられないで
しょ」
『そっか、関数が呼ばれるんなら、関数の中にブレークポイントを付けとけ
ば呼ばれるときにチェックできるんだね』
「これは変数にアクセスする時すべてに言えることなんだけど、関数呼び出
しと違って〈感知できない〉から、チェックが難しいんだよね」
『だから、色々気を付けなきゃいけないってことね』
「そういうこと。まずは、演算子そのものが結構危険なものだって認識を持
つことが大事かな」
『はーい』
「そしたら、どういう部分について気を付けて、どういうことをすればいい
のか見ていきます。まず今の例みたいな、 if や while の場合」
『 = と == ね。でも気を付けるしかないでしょ?』
「そうでもないよ。有名な方法でこういうのがあります」
void CDebugDlg::OnButton1()
{
int i = 0;
if( 0 = i )
{
TRACE( "Hit!\n" );
}
}
『あ、 if の中身、左右逆だ!』
「 == なら普通に比較するから問題なし。 = だと定数値に代入しようとす
るから」
『コンパイルエラーになるわけね、なるほど』
「ただ、僕はあまり使ってないけど」
『え、そなの?』
「だって見にくいし」
『見にくい?』
「変数が左にある方が読みやすいと思うから。この手の問題は、読みやすさ
が下がれば下がるほど見つけにくくなるから、僕としては、ね」
『なんか微妙なところ……』
「書き間違い問題には & と && や | と || とかあったりするから、そう考
えると見やすさ重視かな」
『こういうの違ってても、コンパイルエラーになんないんだね……』
「あとは、 if の話に戻ると、 == を使わないで直接 if に掛けるとかって
方法もあるかな」
void CDebugDlg::OnButton1()
{
int i = 0;
if( i )
{
TRACE( "Hit!\n" );
}
}
「でもま、今読みやすさが重要だって言ったけど、この if の使い方も、
0 か 0 以外かって、結構混乱しやすいと思うんだよね」
『つまり、 i がどうだったらどうするのか、とかだよね。これって頭こん
がらがるよねー』
「他にも < か > かとか」
『そうそう、〈5以下か10以上〉とか、この前 || 使った方法教えても
らったけど、自分でやってみるとすんごくこんがらがる!』
「僕は数直線を想像するようにしてます」
『数直線?』
「定規の目盛りみたいなの。たとえばこんな感じ」
void CDebugDlg::OnButton1()
{
int i = 13;
if( ( i <= 5 ) || ( 10 <= i ) )
{
TRACE( "Hit!\n" );
}
// Hit!
}
「この if の中身、 5 >= i とか i >= 10 とかしても動くでしょ」
『そだよね。でもこう書いた理由があるってことだよね』
「そう。たとえば定規で」
++++++++++++++++++++++++++++++++++++
-10 -5 0 5 10
「って右側が大きい数になるように定規を置いたとき、この例で当たるのの
範囲は」
||||||||||||||||||||||| ||||||||
++++++++++++++++++++++++++++++++++++
-10 -5 0 5 10
「の | がある範囲が当たりだよね。 i <= 5 || 10 <= i は、その通りに並
べてるわけ」
『 5 >= i や i >= 10 だと確かにこの図と違ってきちゃうね』
「 5 >= i || 10 <= i だと」
『書けない……』
「まー 5 >= i || i >= 10 でもいいけど、数学だと右に大きな数が来るこ
とが多いから」
『グラフなんかも左から右って多いしね。あとさ、この数直線って、結構分
かりやすいかも』
「そだね、それをそのままプログラムに置き換えると、僕が書いたようにな
るかな」
『実際に、書けるかな……』
「大丈夫だよ。 > や >= は使わない、って憶えとけば」
『そっか、右の方が大きな数字になるから > は >= は絶対使わないんだ』
「それさえ憶えてれば大丈夫でしょ」
『あ、あと、たとえば for で5周させたいとき……』
void CDebugDlg::OnButton1()
{
for( int iF1 = 0; iF1 < 5; iF1++ )
{
TRACE( "%d ", iF1 );
}
// 0 1 2 3 4
}
『これは iF1 < 5 だけど、 iF1 <= 4 でも iF1 != 5 でも5周するで
しょ。どれ使うのがいいの?』
「これは難しいかなー。まず、〈5周〉ってことが分かりやすいように、
iF1 <= 4 を使わないことが多いかな」
『 5 って数字が書いてあった方が分かりやすいってことね』
「 iF1 < 5 か iF1 != 5 は難しいところかな。 iF1 < 5 だと〈 5 未満の
間〉、 iF1 != 5 だと〈 5 にたどり着いてない間〉って意味になるから、
その意味に合った方を選ぶのがいいかなー」
『意味?』
「そう、これ大事。〈意味〉、英語で〈セマンティクス〉って言うんだけ
ど、プログラムって、字面の奥に隠された〈意味〉が存在するんだよね」
『普通の言葉で言うと、〈アリガト〉が感謝なのか皮肉なのか、って違いみ
たいな?』
「そこまでは細かくないけど、それに近い感じ。 < と != 、機能的には同
じでも意味が違ってくるし、それがプログラムの読みやすさに大きく関わっ
てくるから」
『そうなんだね。 for だと……結局どっちがいいってわかんないね』
「まーね。僕が < の方を使う理由は、万が一 iF1 が ストップさせる数字
を飛び越えちゃった時でも止まるようにしたいから」
『そっか、 != だと iF1 が 4 の次 6 になったら無限ループしちゃうん
だ』
「滅多にないけど、ループの中でうっかり iF1 に足してたりすると」
『なんかありそう……。あとさ、こういうのはどう?』
void CDebugDlg::OnButton1()
{
for( int iF1 = 1; iF1 <= 5; iF1++ )
{
TRACE( "%d ", iF1 );
}
// 1 2 3 4 5
}
『こんな感じに 1 からってのはどう? 見やすさは一番じゃないかなーと
思うんだけど』
「5周ループって使い道だけならいいけど、 iF1 を配列とかに使えない
よ?」
『そういえば。これも 1 から始まっててさっきのと結果違うし』
「配列を使うか使わないかで使い分けると混乱すると思うから、僕は 0 か
らって方を勧めるかな。でもこっちの方が分かりやすいってこともあるから
その辺は臨機応変」
『臨機応変って言ったらなんでもそうなっちゃうじゃん』
「ま、そうだけどね。残りは次回!」
/*
Preview Next Story!
*/
『なんだかんだ言って……』
「ん?」
『水希ちゃんのプログラムってよく考えられてるってゆーか』
「四六時中プログラムのことばっか考えてると、ね」
『それもちょっと……』
「だから、火美ちゃんは聞いて憶えて考えて選んで使えばいいわけ」
『……いーの?それで?』
「というわけで次回」
< Version 6.13 手抜きをするな! >
『につづく!』
「ノウハウを教えていかなきゃ、いいプログラマー増えないでしょ」
『なんかもったいないなー』