当前位置:  编程技术>c/c++/嵌入式

关于C/C++中可变参数的详细介绍(va_list,va_start,va_arg,va_end)

    来源: 互联网  发布时间:2014-10-21

    本文导语:  由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载。对这种情况,提出了指针参数来解决问题。 如printf()函数,其原型为:int   printf(   const ...

由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦,即使采用C++,如果参数个数不能确定,也很难采用函数重载。对这种情况,提出了指针参数来解决问题。

如printf()函数,其原型为:
int   printf(   const   char*   format,   ...);

它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:  
printf( "%d ",i);  
printf( "%s ",s);  
printf( "the   number   is   %d   ,string   is:%s ",   i,   s);  

如何实现其功能?

我们需要以下几个宏定义:

(1)va_list
定义了一个指针arg_ptr, 用于指示可选的参数.

(2)va_start(arg_ptr, argN)
使参数列表指针arg_ptr指向函数参数列表中的第一个可选参数,argN是位于第一个可选参数之前的固定参数, 或者说最后一个固定参数.如有一va函数的声明是void va_test(char a, char b, char c, ...), 则它的固定参数依次是a,b,c, 最后一个固定参数argN为c, 因此就是va_start(arg_ptr, c).

(3)va_arg(arg_ptr, type)
返回参数列表中指针arg_ptr所指的参数, 返回类型为type. 并使指针arg_ptr指向参数列表中下一个参数.返回的是可选参数, 不包括固定参数.

(4)va_end(arg_ptr)
清空参数列表, 并置参数指针arg_ptr无效.

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

也需你现在还是不能理解,别着急,现在从一个实例着手.定义这么一个函数,函数的第一个参数是固定的,其余参数是可变的。定义为:
void   simple_va_fun(int i,...); 其代码为:

代码如下:

#include
#include
using namespace std;
void simple_va_fun(int i,...);

int main(int argc,char *argv[])
{
    simple_va_fun(100);  
    simple_va_fun(100,200);
    simple_va_fun(100,200,'a');
    return 0;
}

void simple_va_fun(int i,...)  
{  
    va_list   arg_ptr;   //定义可变参数指针
    va_start(arg_ptr,i);   // i为最后一个固定参数
    int j=va_arg(arg_ptr,int);   //返回第一个可变参数,类型为int
    char c=va_arg(arg_ptr,char);   //返回第二个可变参数,类型为char
    va_end(arg_ptr);        //  清空参数指针
    printf( "%d %d %cn",i,j,c);  
    return;  
}


代码运行解释:  
(1)首先在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针.

(2)然后用va_start宏初始化变量arg_ptr,这个宏的第二个参数是第一个可变参数的前一个参数,是一个固定的参数.

(3)然后用va_arg返回第一个可变的参数,并赋值给整数j。va_arg的第二个参数是你要返回的参数的类型,这里是int型.  返回第一个可变参数后arg_ptr指向第二个可变参数,用同样的方法返回并赋值给c,类型为char类型。

(4)最后用va_end宏结束可变参数的获取。

小结:
可变参数的函数原理其实很简单,而va系列是以宏定义来定义的,实现跟堆栈相关.我们写一个可变函数的C函数时,有利也有弊,所以在不必要的场合,我们无需用到可变参数.如果在C++里,我们应该利用C++的多态性来实现可变参数的功能,尽量避免用C语言的方式来实现。

附加:

参数在堆栈中分布:
在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的. 总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段. 堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:

最后一个参数
倒数第二个参数
...
第一个参数
函数返回地址
函数代码段


    
 
 

您可能感兴趣的文章:

  • Python函数默认参数和字典参数及可变参数(带星号参数)
  • java可变参数使用示例
  • C++可变参数模板(variadic template)详细介绍及代码举例
  • 用C#的params关键字实现方法形参个数可变示例 iis7站长之家
  • shell中的可变参数问题
  • c++11可变参数使用示例
  • 如何定义一个可变参数的自定义函数
  • c# 方法可变数量的参数
  • 用c语言根据可变参数合成字符串的实现代码
  • c语言可变参数实现示例
  • C/C++宏定义的可变参数详细解析
  • aix53中宏中使用可变参数的问题
  • Java方法的可变参数类型实例分析
  • C++可变参数的函数与模板实例分析
  • 立即送分!如何实现象printf(char * ,...),的可变的参数????????
  • C++可变参数的实现方法
  • C/C++可变参数的使用
  • C/C++中可变参数的用法详细解析
  • 浅析C/C++中的可变参数与默认参数
  • C语言可变参数函数详解示例
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • java 方法能不能让像c中那样:行参是可变的(指的是个数和类型)
  • Java不可变List类型 JavaTuples
  • java虚拟机的内存大小是否可变
  • 怎么把一个可变长的字符串的最后一位付给另外一个变量?
  • nohup 日志能否 可变
  • 关于可变长数组VLA的一点疑问
  • 请问如何在jsp中include一个可变的变量文件名,谢谢!
  • 用C或C++编程,模拟可变分区存储管理且首次适应的算法实现存储器的分配与回收
  • 深入Java不可变类型的详解
  • 在可变式分区分配方案中,只需要进行一次比较就可以判定系统是能否满足作业对主存空间要求的是( )。
  • "Integer对象是不可变的"-----关于final和封装器的问题,望高手指点!
  • 不可变数据集合 Immutable.js
  • 用C#的params关键字实现方法形参个数可变示例
  • 深入同步访问共享的可变数据分析
  • Java的string类为什么是不可变的
  • C#不可变类型深入解析
  • PHP变量的定义、可变变量、变量引用、销毁方法


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3