Provided by: manpages-ja-dev_0.5.0.0.20180315+dfsg-1_all
名前
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_copy() マクロは (初期化済みの) 可変長引き数リスト src を dest にコピーする。動作は、 last 引き数に dest を渡して va_start() を dest に適用し、それから src が現在の状態に達する までに呼び出したのと同じ回数だけ va_arg() を呼び出す、のと同じことを行う。 すぐ分かる 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 を用いるシステムも ある。
属性
マルチスレッディング (pthreads(7) 参照) マクロ va_start(), va_arg(), va_end(), va_copy() はスレッドセーフである。
準拠
va_start(), va_arg(), va_end() マクロは C89 準拠である。 va_copy() は C99 で定義されてい る。
注意
これらのマクロは、以前から用いられてきた同等のマクロ群と 互換ではない。過去のものと互換な バージョンは、 インクルードファイル <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); }
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.79 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。 2013-12-10 STDARG(3)