最後の引数として省略記号 (...) を持つ関数宣言は、可変数の引数を受け取ります。 C++ では、明示的に宣言された引数に対してのみ型チェックが提供されます。 関数の引数の数と型が異なる場合は、可変引数リストを使用できます。
printf
関数ファミリは、可変引数リストを持つ関数の例です。
可変個の引数を取る関数
宣言された後の引数にアクセスするには、この記事で説明するように、標準インクルード ファイル <stdarg.h>
に含まれているマクロを使用します。
Microsoft 固有の仕様
Microsoft C++ では、省略記号が最後の引数であり、省略記号の前にコンマが含まれる場合は、省略記号を引数として指定できます。 したがって、宣言 int Func( int i, ... );
は有効ですが、 int Func( int i ... );
は有効ではありません。
Microsoft 固有の仕様はここまで
可変数の引数を受け取る関数の宣言には、使用されていない場合でも、少なくとも 1 つのプレースホルダー引数が必要です。 このプレースホルダー引数が指定されていない場合、残りの引数にアクセスする方法はありません。
char
型の引数が変数引数として渡されると、int
型に変換されます。 同様に、 float
型の引数を変数引数として渡すと、 double
型に変換されます。 他の型の引数は、通常の整数および浮動小数点の上位変換を受ける可能性があります。 詳細については、「 標準変換」を参照してください。
変数リストを必要とする関数は、引数リストで省略記号 (...) を使用して宣言されます。 変数リストによって渡される引数にアクセスするには、 <stdarg.h>
インクルード ファイルで説明されている型とマクロを使用します。 これらのマクロの詳細については、「va_arg、va_copy、va_end、va_start」を参照してください。
次の例は、マクロを使用して可変引数リストを処理する方法を示しています。
// variable_argument_lists.cpp
#include <stdio.h>
#include <stdarg.h>
// Declaration, but not definition, of ShowVar.
void ShowVar( char *szTypes, ... );
int main() {
ShowVar( "fcsi", 32.4f, 'a', "Test string", 4 );
}
// ShowVar takes a format string of the form
// "ifcs", where each character specifies the
// type of the argument in that position.
//
// i = int
// f = float
// c = char
// s = string (char *)
//
// Following the format specification is a variable
// list of arguments. Each argument corresponds to
// a format character in the format string to which
// the szTypes parameter points
void ShowVar( char *szTypes, ... ) {
va_list vl;
int i;
// szTypes is the last argument specified; you must access
// all others using the variable-argument macros.
va_start( vl, szTypes );
// Step through the list.
for( i = 0; szTypes[i] != '\0'; ++i ) {
union Printable_t {
int i;
float f;
char c;
char *s;
} Printable;
switch( szTypes[i] ) { // Type to expect
case 'i':
Printable.i = va_arg( vl, int );
printf_s( "%i\n", Printable.i );
break;
case 'f':
Printable.f = va_arg( vl, double );
printf_s( "%f\n", Printable.f );
break;
case 'c':
Printable.c = va_arg( vl, char );
printf_s( "%c\n", Printable.c );
break;
case 's':
Printable.s = va_arg( vl, char * );
printf_s( "%s\n", Printable.s );
break;
default:
break;
}
}
va_end( vl );
}
32.400002
a
Test string
前の例は、次のような重要な概念を示しています。
- いずれかの可変個引数がアクセスされる前に、型
va_list
の変数としてリスト マーカーを確立する必要があります。 前の例では、マーカーはvl
と呼ばれます。 - 個々の引数は
va_arg
マクロを使用してアクセスします。 スタックから正しいバイト数を転送できるように、取得する引数の型をva_arg
マクロで指定する必要があります。 呼び出し元プログラムによってva_arg
に指定された型とは異なるサイズの正しくない型を指定した場合、結果は予測不能となります。 -
va_arg
マクロを使用して取得した結果を、必要な型に明示的にキャストする必要があります。 -
va_end
マクロを呼び出して、可変引数処理を終了する必要があります。