リスト8−8は、別の人のプログラムですが、このパターンは、しばしば見かけます。リスト8 −9が実際に呼び出している例です。これから、デバッグのために何やら表示でもさせようという のが読みとれます。
リスト8−8 十分な数の引数 |
1 void 2 debugprint(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16) 3 int s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16; 4 { 5 extern int debug_print_on; 6 7 if(! debug_print_on) return; 8 fprintf(stderr,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16); 9 } |
リスト8−9 引数が不定個数の関数の呼び出し |
1 debugprint( "*** window_create unknown type\n"); 2 3 debugprint( "win_argv_set() --- unknown argv option %s\n", *argv ); 4 5 debugprint( "win_set_size id[%x] W=%d, H=%d\n", win, width, height); 6 7 debugprint( "font_open >>%s<< [%x]\n", fontname, font ); |
関数debugprintは、第1引数が fprintf の書式になっていて、第2引数以降が、その書式に対 応するデータです。fprintf で直接書いていない理由は、デバッグメッセージ表示フラグ debug_print_on の値によって、表示の有無を切替えるため、関数呼び出しにしています。16個も の整数引数を並べているのは、「このくらい並べておけば、不足することはないだろう」との考え でしょう。
でも、これでは、ANSIに従い、関数のプロトタイプ宣言をしてしまうと、コンパイルエラーで引っ かかってしまいます。いえ、それだけではありません。リスト8−9を見ると、引数の型は、最初 は文字列(char*)であり、それ以降はいろいろ考えられます。要するに、不定なのです。なのに、 関数debugprintの引数の宣言は、全部int型にしています。
一応、これで偶然動作しているようですが、移植性の極度に低い書き方です。
最近のコンパイラなら、可変個数引数を処理するためのヘッダーファイル
これを使えば、第1引数は printf関数などで指定する書式なので、そのように引数に書きます。
第2引数以降は、任意個数の引数が書けます。これを、引数中には va_alist、引数の宣言には、
va_dclだけを書きます。これだけでは、何のことだか良く分からないでしょう。
そこで、ちょっと、vfprintfという、可変書式つき関数の仕様を見てみましょう。
関数引数の宣言で、おまじないをしましたが、このおかげで、va_start( ap ); とするだけで、
ap が可変個数引数へのポインタとなっています。後は、これをvfprintfの3番目に書けば良いだ
けです。最後の va_end( ap ); は無くても動きますが、それは行儀作法として良くありませんの
で、書いておきましょう。
可変個数引数の扱いは、慣れないうちは理解し難いと思います。まだ、きちんと使用している方
も少ないようです。実は、第7回目に使用していた個所がありましたが、気づかれましたか。可変
個数引数の利用範囲は広範なので、是非慣れていただきたいと思います。今すぐ、きちんと理解し
たい人は、例の「プログラミング言語C第2版」と、ご自分のシステムのインクルードファイルで
勉強してください。
ここまで無料で閲覧できましたが、著者に恩義を
感じ、本書を閲覧してお気に召しましたら、他の者にも本ページの存在を知ら
せるする義務がございます。いいですね。忘れちゃ
いけませんよ。たいした手間ではないでしょう?
リスト8−10 引数が不定個数の関数
1 #include <stdio.h>
2 #include <varargs.h>
3
4 void
5 debugprint( fmt, va_alist )
6 char *fmt;
7 va_dcl
8 {
9 extern int debug_print_on;
10 va_list ap;
11
12 if( ! debug_print_on ) return;
13 va_start( ap );
14 vfprintf( stderr, fmt, ap );
15 va_end( ap );
16 }
int vfprintf(stream, format, ap)
FILE *stream;
char *format;
va_list ap;
fprintfと同じようですが、最後だけ変な記述になっています。じつは、ここに可変個数引数への
ポインタが書けるのです。debugprint では、第2引数へのポインタをvfprintfに渡せば、その後
の引数は、ユーザは気にしなくても、書式を調べながら、必要に応じてdebugprintの引数を順に使っ
てくれます。
■参考文献■
Copyright1996 Hirofumi Fujiwara. No reproduction or republication
without written permission
『Cプログラミング診断室』目次/
次(第9章 珠玉の力作 プログラムの紹介)