包含变量自变量列表的函数 (C++)

具有省略号(...)作为最后一个参数的函数声明采用可变数量的自变量。 C++仅为显式声明的参数提供类型检查。 当函数的参数数量和类型可能有所不同时,可以使用变量参数列表。 函数 printf 系列是具有变量参数列表的函数的示例。

包含变量自变量的函数

若要在声明参数后访问参数,请使用标准 include 文件 <stdarg.h> 中包含的宏,如本文所述。

Microsoft 专用

Microsoft C++允许将省略号指定为参数(如果省略号是最后一个参数),并且省略号位于省略号之前。 因此,声明 int Func( int i, ... ); 是合法的,但 int Func( int i ... ); 不是。

结束 Microsoft 专用

采用可变数量的参数的函数的声明至少需要一个占位符参数,即使它未使用。 如果未提供此占位符参数,则无法访问其余参数。

当类型的 char 参数作为变量参数传递时,它们将转换为类型 int。 同样,当类型的 float 参数作为变量参数传递时,它们将转换为类型 double。 其他类型的自变量受常见整型和浮点型提升的限制。 有关详细信息,请参阅 标准转换

使用参数列表中的省略号 (...) 来声明需要变量列表的函数。 使用 <stdarg.h> include 文件中描述的类型和宏来访问通过变量列表传递的参数。 有关这些宏的详细信息,请参阅 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

上一个示例演示以下重要概念:

  1. 在访问任何变量参数前,必须建立一个列表标记作为类型 va_list 的变量。 在前面的示例中,该标记称为 vl
  2. 使用 va_arg 宏访问各个参数。 必须告知 va_arg 宏要检索的参数的类型,以便它可以从堆栈中传输正确的字节数。 如果为 va_arg 指定的大小的类型与通过调用程序提供的类型不同,则结果是不可预知的。
  3. 应将使用 va_arg 宏获取的结果显式强制转换为所需类型。
  4. 必须调用 va_end 宏以终止变量参数处理。