C++不定参数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++不定参数相关的知识,希望对你有一定的参考价值。

本人初学。。。
希望了解一下如何使用含有不定数目个参数的函数,
请举例说明;
比如:
输入若干不定数目的整数,求其和、方差、标准差、极差。

最好使用#include<iostream.h>的语句

C/C++语言有一个不同于其它语言的特性,即其支持可变参数,典型的函数如printf、scanf等可以接受数量不定的参数。如:

printf ( "I love you" );
printf ( "%d", a );
printf ( "%d,%d", a, b );

第一、二、三个printf分别接受1、2、3个参数,让我们看看printf函数的原型:

int printf ( const char *format, ... );

从函数原型可以看出,其除了接收一个固定的参数format以外,后面的参数用"…"表示。在C/C++语言中,"…"表示可以接受不定数量的参数,理论上来讲,可以是0或0以上的n个参数。

本文将对C/C++可变参数表的使用方法及C/C++支持可变参数表的深层机理进行探索。

可变参数表的用法

1、相关宏

标准C/C++包含头文件stdarg.h,该头文件中定义了如下三个宏:

void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */
type va_arg ( va_list arg_ptr, type );
void va_end ( va_list arg_ptr );

在这些宏中,va就是variable argument(可变参数)的意思;arg_ptr是指向可变参数表的指针;prev_param则指可变参数表的前一个固定参数;type为可变参数的类型。va_list也是一个宏,其定义为typedef char * va_list,实质上是一char型指针。char型指针的特点是++、--操作对其作用的结果是增1和减1(因为sizeof(char)为1),与之不同的是int等其它类型指针的++、--操作对其作用的结果是增sizeof(type)或减sizeof(type),而且sizeof(type)大于1。

通过va_start宏我们可以取得可变参数表的首指针,这个宏的定义为:

#define va_start ( ap, v ) ( ap = (va_list)&v + _INTSIZEOF(v) )

显而易见,其含义为将最后那个固定参数的地址加上可变参数对其的偏移后赋值给ap,这样ap就是可变参数表的首地址。其中的_INTSIZEOF宏定义为:

#define _INTSIZEOF(n) ((sizeof ( n ) + sizeof ( int ) - 1 ) & ~( sizeof( int ) - 1 ) )

va_arg宏的意思则指取出当前arg_ptr所指的可变参数并将ap指针指向下一可变参数,其原型为:

#define va_arg(list, mode) ((mode *)(list =\
(char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &\
(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]

对这个宏的具体含义我们将在后面深入讨论。

而va_end宏被用来结束可变参数的获取,其定义为:

#define va_end ( list )

可以看出,va_end ( list )实际上被定义为空,没有任何真实对应的代码,用于代码对称,与va_start对应;另外,它还可能发挥代码的"自注释"作用。所谓代码的"自注释",指的是代码能自己注释自己。

下面我们以具体的例子来说明以上三个宏的使用方法。

2、一个简单的例子

#include <stdarg.h>
/* 函数名:max
* 功能:返回n个整数中的最大值
* 参数:num:整数的个数 ...:num个输入的整数
* 返回值:求得的最大整数
*/
int max ( int num, ... )

int m = -0x7FFFFFFF; /* 32系统中最小的整数 */
va_list ap;
va_start ( ap, num );
for ( int i= 0; i< num; i++ )

int t = va_arg (ap, int);
if ( t > m )

m = t;


va_end (ap);
return m;

/* 主函数调用max */
int main ( int argc, char* argv[] )

int n = max ( 5, 5, 6 ,3 ,8 ,5); /* 求5个整数中的最大值 */
cout << n;
return 0;


函数max中首先定义了可变参数表指针ap,而后通过va_start ( ap, num )取得了参数表首地址(赋给了ap),其后的for循环则用来遍历可变参数表。这种遍历方式与我们在数据结构教材中经常看到的遍历方式是类似的。

函数max看起来简洁明了,但是实际上printf的实现却远比这复杂。max函数之所以看起来简单,是因为:

(1) max函数可变参数表的长度是已知的,通过num参数传入;

(2) max函数可变参数表中参数的类型是已知的,都为int型。

而printf函数则没有这么幸运。首先,printf函数可变参数的个数不能轻易的得到,而可变参数的类型也不是固定的,需由格式字符串进行识别(由%f、%d、%s等确定),因此则涉及到可变参数表的更复杂应用。

下面我们以实例来分析可变参数表的高级应用。

参考资料:http://www.diybl.com/course/3_program/c++/cppsl/2008520/117226.html

参考技术A #include <conio.h>
#include <stdarg.h>
#include <iostream>
using namespace std;

/************************************************************************/
/*  
type va_arg(va_list argptr, type);
  void va_end(va_list argptr);
  void va_start(va_list argptr, last_parm);
都包含在头文件<stdarg.h>中
任何可变长度的变元被访问之前,必须先用va_start()初始化变元指针argptr
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址
  #define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效
*/
/************************************************************************/

void test()

double a;
a = 1.1;
int b = *(int*) & a;
cout << (void*)&a << " " << (void*)&b << endl;


int sum(int i,...)

int count;//参数个数
int ra;
int inst;
va_list markr;
va_start(markr, i);//获取地址
ra = (*(int *)((int)markr - 8));//获得栈顶返回值
inst = (*(int *)(*(int *)((int)markr - 8)));//获取指令
count = ((inst&0xff0000)>>16)/4;//得到参数个数
cout << "参数个数是:" << count << endl;
va_end(markr);//释放
va_list arg_ptr;
va_start(arg_ptr, i);
int* first;
first = &i;
int m;
m =* first;//首先把第一个参数加上
int j=0;
while (1)

if(j >= (count-1))
break;
m+=va_arg(arg_ptr, int);
//这里 va_arg(arg_ptr, int)是从第二个参数开始递加返回
j++;

va_end (arg_ptr);
return m;


int sumi(int val, ...)

va_list ap;
va_end(ap);//置空
cout << "ap=" << (void*)ap << endl;
cout << "&val=" << (void*)&val << endl;
va_start(ap,val);//va_start执行完毕后,ap指向变量val后第一个4字节对齐的地址
cout << "va_start(ap,val)=" << (void*)va_start(ap,val) << endl;
int sum = val;
cout << "sum=" << sum << endl;
cout << "ap=" << (void*)ap << endl;
val = va_arg(ap, int);//使ap指向当前变量的下一个变量
cout << "ap=" << (void*)ap << endl;

while(0 != val)

sum = sum + val;
val = va_arg(ap,int);

return sum;


int maxi(int val, ...)

va_list vl;
va_start(vl, val);//va_start执行完毕后,vl指向变量val后第一个4字节对齐的地址
int max = val;
int inst = (*(int *)(*(int *)((int)vl - 8)));//获取指令
int count = ((inst&0xff0000)>>16)/4;//得到参数个数
for (int i = 0; i < count-1; i++)

val = va_arg(vl, int);//使vl指向当前变量的下一个变量
//cout << val << endl;
if (val > max)

max = val;

//cout << "max: " << max << endl;

va_end(vl);//置空vl
return max;


int fun2(const char *ch,int num,...)

va_list ap;
va_start(ap,num);
va_list app = va_arg(ap, va_list);//获取下一层参数
cout << ch << endl;
for(int i=0;i<num;i++)

int t = va_arg(app,int);
cout << t << " ";

cout << endl;

va_end(ap);
return 0;


int fun1(const char *ch,int num,...)

va_list ap;
va_start(ap,num);
//不定参数之间之间传递参数
fun2(ch,num,ap);
va_end(ap);
return 0;


int main(int argc, char* argv[])

//这里的sum参数可以任意个
cout << sum(35,40,20,10,100,1,2,3,4,10,20,30,40) << endl;
cout << sumi(35,40,20,10,100,1,2,3,4,10,20,30,40,0) << endl;
cout << "max(35,40,20,10,100,1,2,3,4,10,20,30,40) = " << maxi(35,40,20,10,100,1,2,3,4,10,20,30,40) << endl;
fun1("Hello ",6,2,4,3,6,8,9);
test();
getch();
return 0;

以上是关于C++不定参数的主要内容,如果未能解决你的问题,请参考以下文章

有关 java 不定参数

Python 不定长参数 *argc/**kargcs

不定长参数作用

Golang--不定参数类型

不定长参数可变参数

java的不定参数,可变参数Object ...