Provided by: manpages-ja-dev_0.5.0.0.20210215+dfsg-1_all bug

名前

       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  の値として取得する。 引き数 apva_list ap で、 va_start()  によって初期化されてい
       る必要がある。 va_arg() を呼び出すごとに ap は変更され、次回の呼び出しの際に、さらに次の引
       き数を返すようになる。 引き数 type は型の名前である。 type の前に * を付ければ、オブジェク
       トへの型付きポインターが得られる。

       va_start()  マクロの直後に va_arg()  を最初に実行すると、 last  の次の引き数が返る。続けて
       実行すると、残りの引き数がそれぞれ返る。

       次の引き数がなかったり、 type が次の引き数の実際の型と互換でない場合 (デフォルトの引き数変
       換で扱 えなかった場合) には、予測できないエラーが起こる。

       apva_arg(ap,type) の形で関数に渡されると、 ap の値は関数から返って来た後は不定となる。

   va_end()
       va_start()  が実行される毎に、同じ関数内で対応する va_end()   が実行されなければならない。
       va_end(ap) が呼び出された後、変数 ap の値は不定となる。 va_start()  と va_end() の組を何回
       も並べて使うことも可能である。 va_end()  はマクロかもしれないし関数かもしれない。

   va_copy()
       va_copy() マクロは (初期化済みの) 可変長引き数リスト srcdest  にコピーする。動作は、
       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)