『Cプログラミング診断室』目次次(第9章 珠玉の力作 プログラムの紹介)

第8章 Pascalが好き

可変個数の引数


リスト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型にしています。

一応、これで偶然動作しているようですが、移植性の極度に低い書き方です。

最近のコンパイラなら、可変個数引数を処理するためのヘッダーファイル または <varargs.h>が用意されています。以下は、手元にあるSPARCstationの標準のコンパイラを 使用した場合の説明をします。(リスト8−10参照)

 
リスト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	}

これを使えば、第1引数は printf関数などで指定する書式なので、そのように引数に書きます。

第2引数以降は、任意個数の引数が書けます。これを、引数中には va_alist、引数の宣言には、 va_dclだけを書きます。これだけでは、何のことだか良く分からないでしょう。

そこで、ちょっと、vfprintfという、可変書式つき関数の仕様を見てみましょう。

     int vfprintf(stream, format, ap)
     FILE *stream;
     char *format;
     va_list ap;
fprintfと同じようですが、最後だけ変な記述になっています。じつは、ここに可変個数引数への ポインタが書けるのです。debugprint では、第2引数へのポインタをvfprintfに渡せば、その後 の引数は、ユーザは気にしなくても、書式を調べながら、必要に応じてdebugprintの引数を順に使っ てくれます。

関数引数の宣言で、おまじないをしましたが、このおかげで、va_start( ap ); とするだけで、 ap が可変個数引数へのポインタとなっています。後は、これをvfprintfの3番目に書けば良いだ けです。最後の va_end( ap ); は無くても動きますが、それは行儀作法として良くありませんの で、書いておきましょう。

可変個数引数の扱いは、慣れないうちは理解し難いと思います。まだ、きちんと使用している方 も少ないようです。実は、第7回目に使用していた個所がありましたが、気づかれましたか。可変 個数引数の利用範囲は広範なので、是非慣れていただきたいと思います。今すぐ、きちんと理解し たい人は、例の「プログラミング言語C第2版」と、ご自分のシステムのインクルードファイルで 勉強してください。

■参考文献■

[8-1] Xウィンドマニュアル第4巻、 X Toolkit Intrinsics, Programming Manual

[8-2] Xウィンドマニュアル第5巻、 X Toolkit Intrinsics, Reference Manual


ここまで無料で閲覧できましたが、著者に恩義を 感じ、本書を閲覧してお気に召しましたら、他の者にも本ページの存在を知ら せるする義務がございます。いいですね。忘れちゃ いけませんよ。たいした手間ではないでしょう? (^_^)


Copyright1996 Hirofumi Fujiwara. No reproduction or republication without written permission
『Cプログラミング診断室』目次次(第9章 珠玉の力作 プログラムの紹介)