您的位置:首页 > 编程语言 > C语言/C++

c++中如何写参数不定的函数

2016-09-12 15:48 295 查看

#include <stdio.h>
#include <stdarg.h>        //要包含这个头文件
void variable(int i, ...)

{

    int j = 0;

      va_list arg_ptr;    //第1步,定义这个指向参数列表的变量
va_start(arg_ptr, i);//第2步,把上面这个变量初始化.即让它指向参数列表

    while( j != -1 )

      {

        //第3步,获取arg_ptr指向的当前参数.这个参数的类型由va_arg的第2个参数指定
          j = va_arg(arg_ptr, int);

          printf("%d ",j );

      }

      va_end(arg_ptr);    //第4步,做一些清理工作
}

main()

{

      variable(3, 3, 4, 5, 6, -1);

}

//////////////////////////
//////////////////////////
//////////////////////////
///////作为va_list,va_start的练习,可以学习一下使用_vsnprintf函数

#include <stdio.h>
#include <stdarg.h>

void formatoutput(char* format, ...)

{

    char s[10];

      va_list arg_ptr;

      va_start(arg_ptr, format);

      _vsnprintf(s, sizeof(s)-1, format, arg_ptr);

      printf("%s ", s);

}

void main()

{

      formatoutput("%s%s", "d", "g");

}

////////////////////
/////////////////////
参数个数不定的函数,最频繁使用的就是printf()与scanf()。其实,我们也可以自己实现这样的功能,首先看
一个例子:
#include <stdio.h>
#include <stdarg.h>
int Sum(int first, int second, ...)
{

       int sum = 0, t = first;

       va_list vl;

       va_start(vl, first);

       while (t != -1)

       {

         sum += t;

         t = va_arg(vl, int);//将当前参数转换为int类型

      }

      va_end(vl);

      return sum;

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

{

      printf("The sum is %d\n", Sum(30, 20, 10, -1));//-1是参数结束标志

       return 0;

}
在上面的例子中,实现了一个参数个数不定的求int型和的函数Sum()。函数中一开始定义了一个va_list型变量
vl,该变量用来访问可变参数,实际上就是指针,接着使用va_start使vl指向第一个参数,然后再使用va_arg
来遍历每一个参数,va_arg返回参数列表中的当前参数并使vl指向参数列表中的下一个参数。最后通过va_end
把vl指针清为NULL。在这里,va_start,va_arg,va_end其实都是宏,那么这些宏又是如何实现他们的功能的
呢?
一个很显然的问题就是既然参数个数在函数调用之前没有确定,所以,在函数定义的时候没有办法像普通函数
那样使用确定的变量来接受传进来的参数,于是,问题的关键就是如何接收到这些不确定的参数了?首先,看
看函数调用时实际发生的情况,在函数调用的时候,使用栈传递参数,拿上例来说,如果调用Sum(30, 20, 10,
-1),那么参数入栈后的情形如下图所示(假定按照自右至左的顺序入栈):
既然参数在栈中的情形已经知道了,那么,如果使用指针(程序中的vl)指向第一个参数(va_start(vl,
first)),因为所有参数都是连续存放的,通过移动指针就可以访问到每一个参数了(va_arg(vl, int)),这
就是我在程序中使用到那几个宏的实现思想。
        明白了以上原理之后,就可以完全不使用宏,自己实现这样的一个功能了,下面的程序是我按照上面的
思想改写的:
#include <stdio.h>
int Sum(int first, int second, ...)

{

int sum = 0, t = first;

char * vl;//定义一个指针

vl = (char *)&first;//使指针指向第一个参数

while (*vl != -1)//-1是预先给定的结束符

{

        sum += *(int *)vl;//类型转换

        vl += sizeof(int);//移动指针,使指针指向下一个参数

}

return sum;

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

{

printf("The sum is %d\n", Sum(30, 20, 10, -1));//-1是参数结束标志

return 0;

}

可以看出,通过使用指针的确实现了参数个数不定的函数了,但是程序中还有一个问题,那就是移动指针,在
程序中因为我使用的参数都是相同的int类型,所以可以事先知道访问下一个参数的时候应该移动sizeof(int)
个字节,但是,如果参数的类型不同呢?这的确是个比较麻烦的问题,因为不同的数据类型占用的字节数可能
是不一样的(如double型为8个字符,short int型为2个),所以很难事先确定应该移动多少个字节!但是办法
还是有的,这就是使用指针了,无论什么类型的指针,都是占用4个字节,所以,可以把所有的传人参数都设置
为指针,这样一来,就可以通过移动固定的4个字节来实现遍历可变参数的目的了,至于如果取得指针中的内容
并使用他们,当然也是无法预先得知的了,所以这大概也就是像printf(),scanf()之类的函数还需要一个格式
控制符的原因吧^_^!不过实现起来还是有不少麻烦,暂且盗用vprintf()来实现一个与printf()函数一样功能的
函数了,代码如下:
void myPrint(const char *frm, ...)

{

    va_list vl;

    va_start(vl, frm);

    vprintf(frm, vl);

    va_end(vl);

}

//////////////////////
////////////////////////
书上说,当无法列出传递函数的所有实参的类型和数目时,可用省略号指定参数表(...)

如:void foo(...);

void foo(parm_list,...);

void foo(...)

{

     //...

}

调用:foo(a,b,c);

就是不懂,把a,b,c的值传进函数里面后,用什么变量来接收???如果不能接收,(...)岂不是没意义?

还有就是不明白

int printf(const char*...);

printf("hello,&s\n",userName);

这个c的输出函数是怎么用(...)实现的.

先谢了:)

Re:

首先函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码: 

void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...) 



va_list args; 

va_start(args, pszFormat); 

_vsnprintf(pszDest, DestLen, pszFormat, args); 

va_end(args); 

}
///////////////////////////

一个简单的可变参数的C函数

      先看例子程序。该函数至少有一个整数参数,其后占位符…,表示后面参数的个数不定。在这个例子里,所有的输入参数必须都是整数,函数的功能只是打印所有参数的值。函数代码如下:

//示例代码1:可变参数函数的使用
#include "stdio.h"

#include "stdarg.h"

void simple_va_fun(int start, ...) 



     va_list arg_ptr; 

     int nArgValue =start;

     int nArgCout=0;   //可变参数的数目

     va_start(arg_ptr,start);   //以固定参数的地址为起点确定变参的内存起始地址。

     do 

     {

         ++nArgCout;

         printf("the %d th arg: %d",nArgCout,nArgValue); //输出各参数的值

         nArgValue = va_arg(arg_ptr,int);   //得到下一个可变参数的值

     } while(nArgValue != -1);                

     return; 

}

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

{

     simple_va_fun(100,-1); 

     simple_va_fun(100,200,-1); 

     return 0;

}
下面解释一下这些代码。从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:

⑴由于在程序中将用到以下这些宏: 
void va_start( va_list arg_ptr, prev_param ); 

type va_arg( va_list arg_ptr, type ); 

void va_end( va_list arg_ptr ); 

va在这里是variable-argument(可变参数)的意思。
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件。

⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是存储参数地址的指针.因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。

⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数。

⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后,结合参数的类型,就可以得到参数的值。

⑸设定结束条件,这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,在看完这几个宏的内部实现机制后,自然就会明白。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: