初心者のプログラムを見てつくづく思うのは、しなくても良いコーディングが実に多いことです。 1行で済むところを5行も10行もかけたり、C言語で標準サポートされている関数と同様のもの を作っているのをよく見かけます。誰しも欲しいと思われるものは、かなり用意されています。 自分で新たな関数を作ったりすると、そのデバッグが必要になりますが、標準を使えばその必要 もなくなります。当然プログラムも短くなり、バグも入りにくくなります。先人の知恵をしっかり 活用して「楽」をしましょう。 「作らなければ、バグは入らない。」という絶対的真理を悟るべきです。
■sprintf、sscanf を使おう■標準入出力関数のprintfは誰でも知っていますね。それとほとんど同一の関数で、sprintfがあ りますが、この関数をなかなか使いこなしていません。 元のプログラムは、strcpy、strcat、strsetの洪水ですね。個々の関数の機能があまりにも小さ いために、もうプログラムの見通しが全然立ちません。典型的な例は、485〜492行の次の部分でしょ う。
itoa(cn,tnn,16); if(cn < 16) { strcpy(tnnr,"0"); strcat(tnnr,tnn); strcpy(tnn,tnnr); } tnn = strupr(tnn); strcpy(tn,tnn); 上の処理は255以下の正整数cnを16進数2桁の文字列にする処理です。あまりに複雑な処理を行なっ ているので、最初に見たとき、「何だ、この変な部分は?」と思いました。 以上のことは、
sprintf( tn, "%02X", cn ); で済みます。printfは、変換制御文字列で指定したフォーマットに従って標準出力に文字列を送り 出します。sprintfは、第1引数で指定した文字列にその文字列を入れます。 printfなどは出力用でした。対応する入力用として、scanfなどの関数が用意されています。た いていの場合、scanfを使用しているようですが、scanfは入力をその場で解釈しながら処理するた め、オプション、エラーチェックなど十分にはできません。 一般に、データは改行が押されるまで、行末までが単位になっています。これにもっとも自然に 対応し、かつより柔軟なエラー対応などをするには、まず、1行分をバッファに読み込んでから、 じっくりと解析することでしょう。 それには、gets、fgetsでバッファに1行分読み込み、sscanfでバッファ内容を各変数に取り込 みます。 2つの整数値をaとbに入力するとき、
scanf( "%d%d", &a, &b ); と書きますね。でも、こうすると、必ず2つのデータを入力しないとscanfから戻ってきません。 もし、2番目は不用とか、単に改行のみの入力も可能にしたいと思うと、scanfではどうにもなり ません。getsとsscanfを組み合わせた同様の例をリスト1−2に、その実行結果を図1−3に示し ます。
|
リスト1−2 |
1 #include <stdio.h> 2 3 main() 4 { 5 char buf[80]; 6 int a, b; 7 8 for(;;) { 9 printf( "enter a b : " ); 10 if( gets(buf) == NULL ) 11 break; 12 printf( "length=%d ", strlen(buf) ); 13 switch( sscanf( buf, "%d%d", &a, &b ) ) { 14 case EOF: 15 case 0: 16 printf( "<CR>\n" ); 17 break; 18 case 1: 19 printf( "a=%d\n", a ); 20 break; 21 case 2: 22 printf( "a=%d b=%d\n", a, b ); 23 break; 24 } 25 } 26 printf( "\n" ); 27 } |
図1−3 実行結果 |
enter a b : 10 20 length=5 a=10 b=20 enter a b : 30 length=2 a=30 enter a b : length=0 <CR> enter a b : abc length=3 <CR> enter a b : |
ここでは簡単な例しか示していませんが、一度バッファに読み込んでから解析すれば、非常に強 力で柔軟な処理ができることが分かるでしょう。対話処理をしたり、アスキーファイルの解釈をちゃ んとしたい場合はこの方法に限ります。
今回の修正プログラム(リスト1−5)は、この点については対処していません。これをしてし
まうと、もうプログラムは原型を全くとどめなくなるためです。
■文字のテスト■文字が英字か、数字か、16進数字かなどの判定が必要なことがよくあります。このとき、直接範 囲指定をしている人がいますね。元のプログラムの447行目から、
if((dw>= 0x30) && (dw<= 0x39)) break; if((dw>= 0x41) && (dw<= 0x46)) break; if((dw>= 0x61) && (dw<= 0x66)) break;という文字判定があります。ここは、char型変数dwの内容が16進数文字のときにbreakしたいので す。 まず、文字を表すのに16進数を直接用いるのはまずいですね。'0','9','A','F','a','f'とすべ きでしょう。
if((dw>= '0') && (dw<= '9')) break; if((dw>= 'A') && (dw<= 'F')) break; if((dw>= 'a') && (dw<= 'f')) break; でも、このようにすると、unsigned char型とchar型の違う型の比較になると思って、わざわざ16 進数表記にしたのでしょうか。でも、これでも正解ではありません。 C言語には、文字判定のためのマクロが用意されています。このマクロを使うには、
#include <ctype.h> が必要になります。この関数(マクロ)を使うと、実際に不等号などによる条件判定を行なってい ません。配列を参照するだけなので、非常に高速です。ぜひ一度、ctype.hのファイルの中身を読 んで見てください。ちょっと難しいかもしれません。 このマクロのなかのよく忘れ去られている16進数文字判定の isxdigitマクロ関数を使うと上の 判定は、
if( isxdigit( dw ) ) break; だけになります。極めてシンプルでしょう。 ムダがいかに多いかが分かったでしょうか。ムダなことには努力しないで欲しい。しかし、いか にして楽をするかには努力して欲しい。楽をするためには、多くの知識と経験を必要とします。で も、楽をするための努力は、なかなかすぐには報われないけれど、数カ月、あるいは数年後には、 この努力の差が実力の差になってきます。
|
オープンソース |