有些函数的参数个数是不确定个数的,比如如下声明的函数:
[C++] 纯文本查看 复制代码
void testit ( int i, ...);
int average( int first, ... );
DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...);
这几个函数都有几个共同的特征,参数列表的最后都有 '...',这表示不确定个数的参数列表。
va_arg, va_end, va_start 这几个函数宏正是用来处理上面所述情况。它们的声明如下:
[C++] 纯文本查看 复制代码
type va_arg(
va_list arg_ptr,
type
);
void va_end(
va_list arg_ptr
);
void va_start(
va_list arg_ptr,
prev_param
); // (ANSI version)
void va_start(
arg_ptr
); // (Pre-ANSI-standardization version)
va_list 代表的就是 '...' 省略号部分的参数,它实际上是一个字符指针,在使用 va_start , va_arg 之前,一般都需要定义一个 va_list 的变量,以能在后续中操作这些可选参数。
va_start 用来进行选项参数的初始化,它的第 1 个参数就是事先定义的 va_list 类型变量,第 2 个参数是 '...' 之前的那个参数,比如对于 void testit ( int i, ...); 这个函数,va_start 中的第 2 个参数设为 i;又比如 Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...); 这个函数,在设置 va_start 时,第 2 个参数就是 OptStr 。
如果对所有的可选参数都处理完了,那么就用 va_end 进行一下善后工作,它所做的工作就是使上面的 va_list 定义的可选参数指针置为空。它只有一个参数,就是开始时定义的 va_list 变量。
最重要的一个就是 va_arg ,它负责处理可选参数。它处理这些参数的一般方法是使用一个循环遍历所有的可选参数项,每一次循环就会使可选参数指针指向下一个参数。
下面是一个简单示例(代码来自MSDN,这里不用循环遍历可选参数列表):
[C++] 纯文本查看 复制代码
#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 ); // 这里有问题,第 2 个参数 0xffffffff 不是 int 型
testit( 1, NULL ); // 这里也有问题, 第 2 个参数 NULL 不是字符指针类型
}
运行输出:上面代码里,两次运用 testit() 都有问题。第 1 次使用的 testit() 函数的第 2 个参数是个 unsigned int 型,而不是 int 型,这样就和 va_arg( argptr, int ); 里所声明的不一致。第 2 次使用的 testit() 时,第 2 个参数 NULL 实际上十个 int 型,而非 char * 型,这和 va_arg( argptr, char* ); 里声明的也不一致。虽然这样,但并不会给程序运行带来错误,因为它们在传进 testit() 时会自动被强制转换。然而,在某些编译选项限制下,就会产生异常,并报告类型不匹配。所以,严格的来说,在 testit() 时所传递的第 2 个参数要和函数体内 va_arg() 里说明的一致,所以对于上面的两个问题,可在 main() 中强制转换 0xffffffff 为 int 型,如 (int)0xffffffff ,以及强制转换 NULL 为 char * 型,如 (char *) NULL 。
示例2:
[C++] 纯文本查看 复制代码
#include "stdafx.h"
int average( int first, ... );
int _tmain(int argc, _TCHAR* argv[])
{
/* 可选参数里使用 3 个整数作为参数,-1 作为结束符号 */
printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );
/* 4 个整数作为可选参数 */
printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );
/* 只有 -1 一个可选参数 */
printf( "Average is: %d\n", average( -1 ) );
return 0;
}
/* 返回可选参数列表里所有整数参数的平均数 */
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /*初始化变量参数 */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* 重置变量参数 */
return( sum ? (sum / count) : 0 );
}
运行输出:Average is: 3
Average is: 8
Average is: 0 |