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
); // (deprecated Pre-ANSI C89 standardization version)
パラメーター
type
取得される引数の型。
arg_ptr
引数リストへのポインター。
dest
src
で初期化される引数リストへのポインター
src
dest
へコピーされる、初期化された引数のリストへのポインター。
prev_param
最初の省略可能な引数に先行するパラメーター。
戻り値
va_arg
は現在の引数を返します。 va_copy
、 va_start
、 va_end
は値を返しません。
解説
関数が可変個の引数を受け取る場合、va_arg
、va_copy
、va_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_start
はva_arg
が初めて使用される前に使用する必要があります。va_arg
は次の引数がどこで開始するかを決定するために、type
で指定された位置からarg_ptr
の値を取得し、arg_ptr
のサイズを使用して、リストの次の引数を指すようにtype
をインクリメントします。va_arg
は、リストから引数を取得するために関数内で何回でも使用できます。va_copy
は、現在の状態の引数のリストのコピーを作成します。src
パラメーターは、va_start
で既に初期化済みである必要があります。これはva_arg
の呼び出しで更新されていることは認められますが、va_end
でリセットされていないことが必要です。va_arg
からdest
によって取得される次の引数はsrc
から取得される次の引数と同じです。va_end
は、すべての引数の取得後にポインターをNULL
にリセットします。 その関数が制御を返す前に、va_end
がva_start
かva_copy
で初期化された各引数リストで呼び出される必要があります。
Note
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);
}
va_end(argptr);
}
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*
ではない) です。 ネイティブ コードの場合にプログラムをコンパイルすると、次の出力が生成されます。
-1
(null)
要件
ヘッダー: <stdio.h>
と <stdarg.h>
非推奨のヘッダー: <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;
}
Deviation is: 0.816497
Deviation is: 2.236068
Deviation is: 0.000000