C语言:可变参数编程
2017-11-11 23:14
148 查看
可变参数编程:
一般我们编程的时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的实际参数。但在某些情况下我们希望函数的参数个数可以根据需要确定,因此c语言引入可变参数函数。
典型的可变参数函数的例子有printf()、scanf()等
int printf(constchar *format, ...);
int scanf(constchar *format, ...);
编写可变函数准备:
为了编写可变参数函数,我们通常需要用到头文件下定义的以下函数:
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
其中:
va_list是用于存放参数列表的数据结构。
va_start函数根据初始化last来初始化参数列表。
va_arg函数用于从参数列表中取出一个参数,参数类型由type指定。
va_copy函数用于复制参数列表。
va_end函数执行清理参数列表的工作。
上述函数通常用宏来实现,例如标准ANSI形式下,这些宏的定义是:
typedef char * va_list; //字符串指针
#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 )
下面举一个简单的例子:
求平均数,我们对于求多少个数的平均数未知,所以我们写一个可变参数函数
简单说说可变参数实现原理:
函数的所有参数是存储在线性连续的栈空间中的,基于这种存储结构,这样就可以从可变参数函数中必须有的第一个普通参数来寻址后续的所有可变参数的类型及其值。
按照C标准的说明,支持变长参数的函数在原型声明中,必须有至少一个最左固定参数(这一点与传统C有区别,传统C允许不带任何固定参数的纯变长参数函数),这样我们可以得到其中固定参数的地址。
仅从函数原型我们是无法确定"..."中有几个参数、参数都是什么类型的。回想一下函数传参的过程,无论"..."中有多少个参数、每个参数是什么类型的,它们都和固定参数的传参过程是一样的,简单来讲都是栈操作,而栈这个东西对我们是开放的。这样一来,一旦我们知道某函数帧的栈上的一个固定参数的位置,我们完全有可能推导出其他变长参数的位置
一般我们编程的时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的实际参数。但在某些情况下我们希望函数的参数个数可以根据需要确定,因此c语言引入可变参数函数。
典型的可变参数函数的例子有printf()、scanf()等
int printf(constchar *format, ...);
int scanf(constchar *format, ...);
编写可变函数准备:
为了编写可变参数函数,我们通常需要用到头文件下定义的以下函数:
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
其中:
va_list是用于存放参数列表的数据结构。
va_start函数根据初始化last来初始化参数列表。
va_arg函数用于从参数列表中取出一个参数,参数类型由type指定。
va_copy函数用于复制参数列表。
va_end函数执行清理参数列表的工作。
上述函数通常用宏来实现,例如标准ANSI形式下,这些宏的定义是:
typedef char * va_list; //字符串指针
#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 )
下面举一个简单的例子:
求平均数,我们对于求多少个数的平均数未知,所以我们写一个可变参数函数
int Avg(char n,...) //n的第一个作用用于提示...的位置,n的第二个作用用于记录...数据的个数 { int sum = 0; va_list list; //定义指针,char *list; va_start(list,n); //将指针定位到...的开头 for(int i=0;i { sum = va_arg(list,int); //从...中取数据 } va_end(list); //关闭指针list = NULL; return sum/n; } int main() { printf("%d\n",Avg(1,10)); printf("%d\n",Avg(2,10,20)); printf("%d\n",Avg(3,10,20,30)); printf("%d\n",Avg(4,10,20,30,40)); printf("%d\n",Avg(5,10,20,30,40,50)); }
简单说说可变参数实现原理:
函数的所有参数是存储在线性连续的栈空间中的,基于这种存储结构,这样就可以从可变参数函数中必须有的第一个普通参数来寻址后续的所有可变参数的类型及其值。
按照C标准的说明,支持变长参数的函数在原型声明中,必须有至少一个最左固定参数(这一点与传统C有区别,传统C允许不带任何固定参数的纯变长参数函数),这样我们可以得到其中固定参数的地址。
仅从函数原型我们是无法确定"..."中有几个参数、参数都是什么类型的。回想一下函数传参的过程,无论"..."中有多少个参数、每个参数是什么类型的,它们都和固定参数的传参过程是一样的,简单来讲都是栈操作,而栈这个东西对我们是开放的。这样一来,一旦我们知道某函数帧的栈上的一个固定参数的位置,我们完全有可能推导出其他变长参数的位置
相关文章推荐
- [转载]编程入门:浅谈C语言的可变参数
- c语言可变参数编程
- C语言中的可变参数函数 三个点“…”printf( const char* format, ...) 博客分类: C语言 ANSI C CC++C#D语言编程 第一篇
- 编程基础知识学习———C语言中可变参数的用法
- C语言可变参数编程
- 编程基础知识学习———C语言中可变参数的用法
- C语言可变参数编程之Avg、Myprinf…
- 编程入门:浅谈C语言的可变参数
- c语言中的可变参数编程
- C语言——可变参数
- C语言中可变参数函数实现原理
- 详解C语言可变参数 va_list和_vsnprintf及printf实现
- C语言_可变参数列表解析
- 可变参数编程的三个宏
- 主题六 函数(C语言核心)----34.可变参数列表
- C语言中可变参数的用法
- C语言中 variable argument 可变参数用法
- 转:C语言可变参数实现
- C语言中可变参数函数的设计
- C语言 可变参数