次の方法で共有


va_arg、va_end、va_start

更新 : 2007 年 11 月

可変個引数リストにアクセスします。

type va_arg(
      va_list arg_ptr,
      type 
);
void va_end(
   va_list arg_ptr 
);
void va_start(
   va_list arg_ptr 
);  // (UNIX version)
void va_start(
   va_list arg_ptr,
      prev_param 
); // (ANSI version)

パラメータ

  • type
    取得する引数の型。

  • arg_ptr
    引数リストへのポインタ。

  • prev_param
    省略可能な最初の引数の直前のパラメータ (ANSI のみ)。

戻り値

va_arg マクロは現在の引数を返します。va_start マクロと va_end マクロには戻り値はありません。

解説

va_argva_endva_start の各マクロを使用すると、関数が可変個の引数をとる場合に、移植性の高い方法で関数の引数にアクセスできます。マクロには、STDARG.H で定義されている ANSI C 準拠のマクロと、VARARGS.H で定義されている UNIX System V 準拠のマクロの 2 つのバージョンがあります。これらのマクロは次のとおりです。

  • va_alist
    呼び出される関数のパラメータの名前 (UNIX バージョンのみ)。

  • va_arg
    現在の引数を取得するマクロ。

  • va_dcl
    va_alist の宣言 (UNIX バージョンのみ)。

  • va_end
    arg_ptr をリセットするマクロ。

  • va_list
    STDIO.H で定義されている引数リストへのポインタの typedef。

  • va_start
    省略可能な引数のリストの先頭に arg_ptr を設定するマクロ (UNIX バージョンのみ)。

どちらのバージョンのマクロでも、関数は固定数の必須引数と、その後に続く可変数の省略可能な引数をとると想定します。必須引数は関数の通常のパラメータとして宣言され、パラメータ名でアクセスできます。省略可能な引数には、STDARG.H または VARARGS.H 内のマクロでアクセスします。これらのマクロは、引数リスト内の最初の省略可能な引数へのポインタを設定し、リストから引数を取得し、引数の処理が完了した時点でポインタをリセットします。

STDARG.H で定義されている ANSI C 準拠のマクロの使用方法は、次のとおりです。

  • 関数のすべての必須引数は、通常どおりパラメータとして宣言されます。va_dcl マクロは、STDARG.H のマクロと一緒には使用しません。

  • va_start マクロは、関数に渡される引数リストの最初の省略可能な引数に arg_ptr を設定します。引数 arg_ptr は va_list 型にする必要があります。引数 prev_param は、引数リスト内の最初の省略可能な引数の直前にある必須パラメータの名前です。prev_param が register ストレージ クラスで宣言される場合、マクロの動作は未定義になります。va_arg マクロを初めて使用する前に、va_start マクロを使用する必要があります。

  • va_arg マクロは、arg_ptr で指定した位置から type の値を取得し、次の引数の開始位置を決定する type のサイズを使用して、リスト内の次の引数を指すように arg_ptr をインクリメントします。関数内で va_arg マクロを繰り返し使用して、リストから引数を取得できます。

  • すべての引数の取得後に、va_end マクロはポインタを NULL にリセットします。

VARARGS.H で定義されている UNIX System V 準拠のマクロの場合は、動作が多少異なります。

  • 関数のすべての必須引数は、通常どおりパラメータとして宣言できます。

  • 関数の最後 (または唯一) の引数は、省略可能な引数のリストを表します。このパラメータの名前は va_alist にする必要があります。va_alist の型として定義されている va_list と混同しないでください。

  • va_dcl マクロは、関数定義と関数の始まりの左中かっこ ({) の間で使用します。このマクロは、終端のセミコロンを含めて va_alist のパラメータの完全な宣言として定義されます。したがって、va_dcl マクロの後にはセミコロンを付けないでください。

  • va_start マクロは、関数内で、関数に渡される省略可能な引数のリストの先頭に arg_ptr を設定します。va_arg マクロを初めて使用する前に、va_start マクロを使用する必要があります。引数 arg_ptr は va_list 型にする必要があります。

  • va_arg マクロは、arg_ptr で指定した位置から type の値を取得し、次の引数の開始位置を決定する type のサイズを使用して、リスト内の次の引数を指すように arg_ptr をインクリメントします。関数内で va_arg マクロを繰り返し使用して、リストから引数を取得できます。

  • すべての引数の取得後に、va_end マクロはポインタを NULL にリセットします。

/clr (共通言語ランタイムのコンパイル) を指定してコンパイルする場合、このマクロを使用するプログラムは、ネイティブと共通言語ランタイムの型システムの違いによって、予期しない結果を生成することがあります。次に例を示します。

#include <stdio.h>
#include <stdarg.h>

void testit ( int i, ...)
{
   va_list argptr;
   va_start(argptr, i);

   if ( i == 0 ) {
      int n = va_arg( argptr, int );
      printf( "%d\n", n );
   } else {
      char *s = va_arg( argptr, char* );
      printf( "%s\n", s);
   }
}

int main()
{
   testit( 0, 0xFFFFFFFF ); // 1st problem: 0xffffffff is not an int
   testit( 1, NULL );       // 2nd problem: NULL is not a char*
}

testit では、2 番目のパラメータが int または char* であることが必要です。渡される引数は 0xffffffff (int ではなく unsigned int) と NULL (実際には char* ではなく int) です。ネイティブ コード用にコンパイルしたプログラムの出力は次のとおりです。

-1
(null)

ただし、/clr:pure を指定してこのプログラムをコンパイルすると、型の不一致による例外が発生します。これを解決するには、次のようにして明示的にキャストを使用します。

int main()
{
   testit( 0, (int)0xFFFFFFFF ); // cast unsigned to int
   testit( 1, (char*)NULL );     // cast int to char*
}

必要条件

ルーチン

必須ヘッダー

省略可能なヘッダー

va_arg

<stdio.h> および <stdarg.h>

<varargs.h>*

va_end

<stdio.h> および <stdarg.h>

<varargs.h>*

va_start

<stdio.h> および <stdarg.h>

<varargs.h>*

* UNIX V との互換性用

互換性の詳細については、「C ランタイム ライブラリ」の「互換性」を参照してください。

ライブラリ

C ランタイム ライブラリのすべてのバージョン。

使用例

// crt_va.c
/* The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_end
 *      va_list             va_dcl (UNIX only)
 */

#include <stdio.h>
#define ANSI            /* Comment out for UNIX version     */
#ifdef ANSI             /* ANSI compatible version          */
#include <stdarg.h>
int average( int first, ... );
#else                   /* UNIX compatible version          */
#include <varargs.h>
int average( va_list );
#endif

int main( void )
{
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

   /* Call with 4 integers. */
   printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );

   /* Call with just -1 terminator. */
   printf( "Average is: %d\n", average( -1 ) );
}

/* Returns the average of a variable list of integers. */
#ifdef ANSI             /* ANSI compatible version    */
int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#else       /* UNIX compatible version must use old-style definition.  */
int average( va_alist )
va_dcl
{
   int i, count, sum;
   va_list marker;

   va_start( marker );            /* Initialize variable arguments. */
   for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
      sum += i;
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#endif

出力

Average is: 3
Average is: 8
Average is: 0

.NET Framework の相当するアイテム

System::ParamArrayAttribute クラス

参照

参照

引数へのアクセス

vfprintf、_vfprintf_l、vfwprintf、_vfwprintf_l