如何获取函数的变长参数(va_list, va_start, va_arg, va_end)
2011-11-25 11:24
411 查看
最近在花时间研读C++。
函数这章讲到了函数的变长参数(ellipsis...),但是primer中讲得比较浅,提到了怎么声明怎么调用,但是没有写明在函数内部是如何获取变长的参数的。
最典型的应用就是printf函数,printf的声明和调用方法如下:
比如printf函数,就是根据第一个参数推导可选实参:如果第一个'%'后有一个's',说明后面要有第二个参数,类型是字符串;如果还有第二个'%',后面跟一个'd',说明还需要第三个参数,是一个整型等等。
所以说,通常情况下,第一个参数是必不可少的。
为了解决变长参数问题,需要用到以下几个宏(以下定义来自MSDN),并且使用这几个宏时必须至少提供一个显式的参数:
其中,type是指要获取的参数的类型,比如int,char *等,arg_ptr是指向参数列表的指针(va_list类型),prev_param是指最后一个显式声明的参数,以用来获取第一个变长参数的位置。
使用步骤:
a)定义一个va_list类型的变量,变量是指向参数的指针。
b)va_start初始化刚定义的变量,第二个参数是最后一个显式声明的参数。
c)va_arg返回变长参数的值,第二个参数是该变长参数的类型。
d)va_end将a)定义的变量重置为NULL。
注意事项:
a)变长参数的类型和数目不能通过宏来获取,只能通过自己写程序控制。
b)编译器对变长参数函数的原型检查不够严格,会影响代码质量。
代码写得较粗糙,表介意。变长参数问题也就先到这里。
(完)
原创文章,欢迎转载,转载请注明出处:http://www.cnblogs.com/AnnieKim。
函数这章讲到了函数的变长参数(ellipsis...),但是primer中讲得比较浅,提到了怎么声明怎么调用,但是没有写明在函数内部是如何获取变长的参数的。
1)省略号(ellipsis)
在无法给出所有传递给函数的参数的类型和数目时,可以使用省略号(...)指定函数参数表。有如下几种形式:void fun1(int a, double b, ...); //给出确定的几个参数,其他用省略号 void fun2(int a ...); //省略号前有或者没有逗号都是可以的 void fun3(...); //也可以不确定任何参数,但和没有参数是不一样的
最典型的应用就是printf函数,printf的声明和调用方法如下:
int printf( const char *format [,argument]... ); //官方声明 printf("My name is %s, age %d.", "AnnieKim", 24); //调用
2)通用的工作原理
大多数带有变长参数的函数都利用显式声明的参数中的一些信息,来获取调用中提供的其他可选实参的类型和数目。比如printf函数,就是根据第一个参数推导可选实参:如果第一个'%'后有一个's',说明后面要有第二个参数,类型是字符串;如果还有第二个'%',后面跟一个'd',说明还需要第三个参数,是一个整型等等。
所以说,通常情况下,第一个参数是必不可少的。
3)如何获取变长参数
现在,我们要关注的是函数内部的实现细节。当我看到primer这部分的时候还真是好奇实现细节呢,只怪我孤陋寡闻,以前没见过⊙﹏⊙b。为了解决变长参数问题,需要用到以下几个宏(以下定义来自MSDN),并且使用这几个宏时必须至少提供一个显式的参数:
#include <stdarg.h> type va_arg( va_list arg_ptr, type ); void va_end( va_list arg_ptr ); void va_start( va_list arg_ptr, prev_param );
其中,type是指要获取的参数的类型,比如int,char *等,arg_ptr是指向参数列表的指针(va_list类型),prev_param是指最后一个显式声明的参数,以用来获取第一个变长参数的位置。
使用步骤:
a)定义一个va_list类型的变量,变量是指向参数的指针。
b)va_start初始化刚定义的变量,第二个参数是最后一个显式声明的参数。
c)va_arg返回变长参数的值,第二个参数是该变长参数的类型。
d)va_end将a)定义的变量重置为NULL。
注意事项:
a)变长参数的类型和数目不能通过宏来获取,只能通过自己写程序控制。
b)编译器对变长参数函数的原型检查不够严格,会影响代码质量。
4)举个例子
最后举个例子,是自己写的printf函数,只能用于处理'%s'和'%d'。为简单起见,没有做任何异常处理,理解这些宏的使用方法即可。#include <iostream> #include <stdarg.h> using namespace std; void myprintf(const char *format...) { va_list argptr; va_start(argptr, format); //va_start char ch; while (ch = *(format++)) //逐个遍历format字符串 { if (ch == '%') { ch = *(format++); if (ch == 's') { char *name = va_arg(argptr, char *); //va_arg cout<<name; } else if (ch == 'd') { int age = va_arg(argptr, int); //va_arg cout<<age; } } else { cout<<ch; } } cout<<endl; va_end(argptr); //va_end } int main() { myprintf("My name is %s, age %d.", "AnnieKim", 24); return 0; }
代码写得较粗糙,表介意。变长参数问题也就先到这里。
(完)
原创文章,欢迎转载,转载请注明出处:http://www.cnblogs.com/AnnieKim。
相关文章推荐
- 如何获取函数的可变参数(va_list, va_start, va_arg, va_end)
- 函数可变参数va_list、va_start、va_arg、va_end原理及使用方法
- va_arg va_start va_end 获取函数参数内容
- 函数可变参数深入分析之va_list、va_start、va_arg、va_end
- va_start,va_arg,va_end,va_list应用举例--实现可变参数的函数
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- 《C语言接口与实现》实验——可变参数表的使用(va_list, va_start, va_arg, va_end)
- C语言中的可变参数:va_list ,va_start,va_arg,va_end
- C/C++中va_list,va_start,va_arg,va_end等可变参数宏的使用
- 深入C语言可变参数(va_arg,va_list,va_start,va_end)
- 可变参数函数的使用:va_start() , va_end() , va_list
- 可变参数列表(va_list,va_arg,va_copy,va_start,va_end)
- 可变参数的函数,va_start(), va_arg(), va_end()
- 函数的多个参数va_list, va_start, va_avg, va_end的使用
- va_list、va_start、va_arg、va_end等利用宏定义实现可变参数
- printf函数中“va_list 、va_start、 va_arg、 va_end” 使用说明
- C/C++中用va_start/va_arg/va_end实现可变参数函数的原理与实例详解
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- C语言中可变参数的用法——va_list、va_start、va_arg、va_end参数定义
- iOS-可变参数va_list、va_start、va_arg、va_end、NS_FORMAT_FUNCTION(1, 2)