va_arg、va_copy、va_end、va_start

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

type va_arg(
   va_list arg_ptr,
   type 
);
void va_copy(
   va_list dest,
   va_list src
); // (ISO C99 and later)
void va_end(
   va_list arg_ptr 
);
void va_start(
   va_list arg_ptr,
   prev_param 
); // (ANSI C89 and later)
void va_start(
   arg_ptr 
);  // (Pre-ANSI C89 standardization version)

パラメーター

  • type
    取得される引数の型。

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

  • dest
    src で初期化される引数リストへのポインター

  • src
    dest へコピーされる、初期化された引数のリストへのポインター。

  • prev_param
    最初の省略可能な引数に先行するパラメーター。

戻り値

va_arg は現在の引数を返します。 va_copyva_start、および va_end は値を返しません。

解説

関数が可変個の引数を受け取る場合、va_argva_copyva_end、および va_start の各マクロを使用することで、関数は移植性の高い方法で引数にアクセスできます。 このマクロには 2 種類のバージョンがあります。STDARG.H で定義されているマクロは、ISO C99 標準に準拠します。VARARGS.H で定義されているマクロは使用されなくなりましたが、ANSI C89 標準以前に作成されたコードの下位互換性のために残されています。

これらのマクロは、関数が固定の個数の必須の引数の後に、省略可能な引数を可変個数受け取るものと想定します。 必須の引数は、関数の通常のパラメーターのように宣言され、パラメーター名でアクセスできます。 省略可能な引数は、STDARG.H (または、ANSI C89 標準以前に書かれたコードの場合は VARARGS.H) のマクロを使用してアクセスします。これらのマクロは、ポインターを引数リストの最初の省略可能な引数へセットし、リストから引数を取得し引数の処理が終了するとポインターをリセットします。

STDARG.H で定義されている C 標準マクロは次のように使用されます。

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

  • va_arg は次の引数がどこで開始するかを決定するために、arg_ptr で指定された位置から type の値を取得し、type のサイズを使用して、リストの次の引数を指すように arg_ptr をインクリメントします。 va_arg は、リストから引数を取得するために関数内で何回でも使用できます。

  • va_copy は、現在の状態の引数のリストのコピーを作成します。 src パラメーターは、va_start で既に初期化済みである必要があります。これは va_arg の呼び出しで更新されていることは認められますが、va_end でリセットされていないことが必要です。 dest から va_arg によって取得される次の引数は src から取得される次の引数と同じです。

  • すべての引数の取得後、va_end は、ポインターを NULL へのポインターにリセットします。 その関数が制御を返す前に、va_endva_startva_copy で初期化された各引数リストで呼び出される必要があります。

C++ メモ : C++ メモ

VARARGS.H のマクロは使用されておらず、C89 ANSI 規格以前に作成されたコードとの下位互換性のためだけに残されています。それ以外の場合は、STDARGS.H のマクロを使用します。

/clr (共通言語ランタイムのコンパイル) を使用してコンパイルすると、これらのマクロを使用するプログラムでは、ネイティブ言語ランタイムと共通言語ランタイム (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 (unsigned int であり、int ではない) と NULL (実際には int であり、char* ではない) です。 ネイティブ コードの場合にプログラムをコンパイルすると、次の出力が生成されます。

  
  

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

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

必要条件

ヘッダー: <stdio.h と> stdarg.h <>

ヘッダー: Deprecated <varargs.h>

ライブラリ

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

使用例

// crt_va.c
/* Compile with: cl /W3 /Tc crt_va.c
 * The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_copy
 *      va_end              va_list
 */

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

double deviation(int first, ...);

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

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

    /* Call with just -1 terminator. */
    printf("Deviation is: %f\n", deviation(-1));
}

/* Returns the standard deviation of a variable list of integers. */
double deviation(int first, ...)
{
    int count = 0, i = first;
    double mean = 0.0, sum = 0.0;
    va_list marker;
    va_list copy;

    va_start(marker, first);     /* Initialize variable arguments. */
    va_copy(copy, marker);       /* Copy list for the second pass */
    while (i != -1)
    {
        sum += i;
        count++;
        i = va_arg(marker, int);
    }
    va_end(marker);              /* Reset variable argument list. */
    mean = sum ? (sum / count) : 0.0;

    i = first;                  /* reset to calculate deviation */
    sum = 0.0;
    while (i != -1)
    {
        sum += (i - mean)*(i - mean);
        i = va_arg(copy, int);
    }
    va_end(copy);               /* Reset copy of argument list. */
    return count ? sqrt(sum / count) : 0.0;
}

出力

  

同等の .NET Framework 関数

System::ParamArrayAttribute Class

参照

関連項目

引数へのアクセス

vfprintf、_vfprintf_l、vfwprintf、_vfwprintf_l