Provided by: manpages-ja-dev_0.5.0.0.20140515+dfsg-2_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.65 の一部 である。プロジェクトの説明とバグ報告
       に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。

                                                   2013-12-10                                          STDARG(3)