Part 2.変数の定義域(2)
前回、uintとintの違いについて述べたが、uintを使いなさいという意味ではない。違いを意識しなさいということだ。
たとえば個数を表す変数を用意したとしよう。個数はマイナスになることはないから、uintにするのが、正しい。ときどき、わざわざintで引数として受け取って、
if (num<0 || num > max_num) return ;
のように負チェックをしてあるプログラムを見かけるが、最初からuintで受け取ればそんなチェックはいらないのである。
ところが、ループ変数に関しては常にuintにすればいいかと言うとそうでもない。10回まわるループを書いたとしよう。
for( uint i=0; i<10 ; ++i)
ループ変数iの取りうる値は、0から9だと思うかも知れないが、それは違う。取りうる値は、0から10だ。ループを抜け出るときにiは10になっている。このことを意識していないと思わぬところでハマる。
普通はあまり書かないが、たとえば、ループカウンタを1からぶん回したとしよう。
for( uint i=1; i<=10 ; ++i)
このとき、
for( byte i=1; i <= c ; ++i)
(byteとはunsinged charにtypedefしてあると仮定する)c==255だと、このループは永久ループとなるのだ。なぜなら、このループを脱出するためには、iが256という値を取れる必要があるからだ。
なぜこういうことが起きるのだろうか?
理由は簡単だ。ループ変数をインクリメントして、そのループ変数が範囲を超えたかを調べているからである。つまり、上の例の場合、iは1からc + 1までを扱える整数型でなければならない。c == 255ならば i は1から256まで扱える整数型でなければならない。
同様の理由により、ダウンカウントするタイプのループにおいては、
for( int i=num-1; i>=0 ; --i)
iは、num-1から-1までを扱える整数型(すなわち符号付き整数)でなければならない。「だからループ変数はintのほうがいい」だとかいうのはちょっと違うと思う。要するに、上記のルールを正しく理解しておくことが大切なのだ。