Data & Algorithm 今回のお題:
『可変パラメタ』


●概要

多分、C 言語で最初に習う関数って十中八九 "printf" だと思うのですが、 「んじゃ printf 実装してみて」って言われるとさて困る。引数の個数変わるやん。 ちうわけで、これの実装法について勉強してみたわけです。

●内容

プロトタイプ

まず、受け取る側のプロトタイプは、

int function( int arg1, int arg2, ... );

という感じ。"..." の部分には変数がいくつ入っても (0 個でも) OK ということになります。 なお、"..." は必ず最後に置き、かつそれ以外に最低 1 つ引数が必要になるようです。 ンなモン要らんという場合は、ダミーの変数を用意しておけばいいでしょう。
なお、ダミーの変数を使ったときに Warning が出て困るという場合は、

arg1 = arg1;

とかしておくとこれを抑制できたような気がします。姑息だけど。

関数の実体

実体側では、まず va_list 型の変数を一つ宣言しておきます。LSI C のドキュメントでは ap という変数名を使っていましたのでこれを採用します。
次に、関数 (正確にはマクロ) va_start() を呼びます。引数は 2 つで、 第 1 引数には先ほど宣言した va_list 型の変数を、第 2 変数には "..." の一つ前の引数を渡します。これで、変数 ap が初期化されます。

va_list ap;
va_start( ap, arg2 );

さて、実際に変数を引っ張り出すには、関数 va_arg() を呼びます。

type va_arg( va_list ap, type );

この "type" ってのは C++ なんかで割と目にするモノなのですが、 ここには変数の型名を書いてやります。例えば、"int" としてやると、 渡されている変数を int 型として引っ張り出してくれます。

細かいことを言うなら、ap ってのは引数に対するディスクリプタで、va_arg() は ap の指す変数を type 型に変換して返し、ap の指す先を次の変数に移す、ということをやっている、のだと思います。

最後に、ap を使い終わったら関数 va_end() を呼びます。

void va_end(va_list ap);

なお、引き出す変数がなくなった時には、va_arg は NULL を返します。 ただ、int で取り出した数が本当に 0 だったときの判定法が見つかりません。 errorno にも変化はないし……。

実際の例としては、こんな感じ。

/* 渡された文字列を順々に表示 */
void mltputstr( int dummy, ... )
{
  va_list ap;
  char    *str;
  va_start( ap, dummy );

  while( ( str = va_arg( ap, char * ) ) != NULL )
    puts( str );

  dummy = dummy  /* Warning を抑制 */

  va_end( ap );
}

●備考

実際考えてみると、こういうコードを組むことってそんなに多くないのかも。 ルーチンの側から利用できるわけではないんだし……。う〜む。


戻る