STDARG(3) Linux Programmer's Manual STDARG(3)
stdarg, va_start, va_arg, va_end, va_copy - 個数・型が可変な引数リスト
#include <stdarg.h>
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
関数は呼び出しに際して、個数や型が可変な引数をとることがでい襦
インクルードファイル <stdarg.h> では va_list 型が宣言されており、3
つのマクロが定義されている。これらを用いると、
呼び出された関数側では個数や型を知らない引た瑤離螢好箸髻⊇腓飽
つづつ読み込むことがでい襦
呼び出される関数では、 va_list
型のオブジェクトが宣言されていなければならない。このオブジェクトが
va_start(), va_arg(), va_end() の各マクロによって扱われる。
va_start()
va_start() マクロは最初に呼び出さなければならない。これは ap
を初期化し、 va_arg() と va_end() で用いることがでい襪茲Δ砲垢襦
パラメーター last は引-
数リストのうち、可変な部分の直前に置かれるパラメーターの名前であ
る。つまり呼び出された関数が型を知っている最後の引た瑤任△襦
このパラメーターはレジスタ変数や関数、配列として
宣言してはならない。このパラメーターのアドレスが va_start()
マクロで用いられるかもしれないからである。
va_arg()
va_arg() マクロは、呼び出し時に指定された引た瑤里Δ繊
次の位置にあるものを指定した型 type の値として取得する。 パラメーター
ap は va_list ap で、 va_start() によって初期化されている必要がある。
va_arg() を呼び出すごとに ap
は変更され、次回の呼び出しの際に、さらに次の引た瑤鯤屬垢茲Δ砲覆襦
パラメーター type は型の名前である。 type の前に *
を付ければ、オブジェクトへの型付ぅ櫂ぅ鵐燭得られる。
va_start() マクロの直後に va_arg() を最初に実行すると、 last の次の引-
数が返る。続けて実行すると、残りの引た瑤それぞれ返る。
次の引た瑤なかったり、 type が次の引た瑤亮尊櫃侶燭噺澳垢任覆ぞ豺
(デフォルトの引た変換で扱 えなかった場合) には、予測で-
ないエラーが起こる。
ap が va_arg(ap,type) の形で関数に渡されると、 ap
の値は関数から返って来た後は不定となる。
va_end()
va_start() が実行される毎に、同じ関数内で対応する va_end()
が実行されなければならない。 va_end(ap) が呼び出された後、変数 ap
の値は不定となる。 va_start() と va_end()
の組を何回も並べて使うことも可能である。 va_end()
はマクロかもしれないし関数かもしれない。
va_copy()
すぐ分かる va_list の実装は、variadic
な関数のスタックフレームのポインタである。
このような場合(ほとんどはそうである)、
単に以下のようにすればいいように思える。
va_list aq = ap;
残念ながら、(長さ 1の)ポインタの配列として扱うシステムもある。
そのような場合、以下のようにする必要がある。
va_list aq;
*aq = *ap;
最後に、パラメータをレジスタで渡すシステムの場合、 va_start()
でメモリを割り当て、パラメータを格納し、
次のパラメータがどれかを指し示すようにする必要がある。 そして va_arg()
でリストを順番にたどり、 va_end() で割り当てたメモリを開放する。
このような状況に対応するため、C99 では va_copy() マクロを追加し、
前述のような割り当ては以下のように置ご垢┐蕕譴襪茲Δ砲靴拭
va_list aq;
va_copy(aq, ap);
...
va_end(aq);
va_copy() が実行されるごとに、 対応する va_end()
を同じ関数内で実行しなければならない。 この名前はまだ draft proposal なので、
va_copy() の代わりに __va_copy を用いるシステムもある。
va_start(), va_arg(), va_end() マクロは C89 準拠である。 va_copy() は
C99 で定義されている。
これらのマクロは、以前から用いられてい親嬰のマクロ群と
互換ではぁ2甬遒里發里噺澳垢淵弌璽献腑鵑蓮 インクルードファイル
<varargs.h> に存在する。
歴史的なセットアップは以下のとおりである。
#include <varargs.h>
void
foo(va_alist)
va_dcl
{
va_list ap;
va_start(ap);
while (...) {
...
x = va_arg(ap, type);
...
}
va_end(ap);
}
va_start マクロに '{' を含み、 va_end マクロに対応する '}'
を含むシステムもあるので、
この二つのマクロは同じ関数になければならない。
varargs マクロとは異なり、 stdarg マクロでは固定引-
数なしで関数を指定することが許されていない。 これは varargs
ベースのコードを stdarg のコードに書ご垢┐襪箸-
に、面倒な作業のもとになる。 また、すべての引た瑤 va_list
として可変個指定したいような場合 (vfprintf(3) など) にも障害となる。
関数 foo
は書式文字からなる文字列を受け入れ、その書式文字に対応する型で可変個の
引た瑤鯑匹濆み、印字する。
#include <stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
2001-10-14 STDARG(3)