可变参数列表
2017-11-10 16:10
218 查看
可变参数列表
C语言中,我们经常使用的printf函数,是可以输入任意多个参数的,而且当我们要写一个函数去求平均值或者其它,我们有时候要求两个数的平均值,有时候要求三个数的平均值,如果每次都封装一个函数,就很麻烦,所以C语言提供了可变参数
下面是一段求平均值的代码:
打开头文件stdarg.h
可以看到我们使用的va_start,va_arg等都是封装好的宏,再打开<vadefs.h>查看宏具体的实现
va_list就是char*,代码中我们声明一个va_list类型的变量arg,用来访问参数列表的未确定部分
va_start是用来初始化arg变量,把arg变量初始化为可变参数部分的最后一个参数,从源码中可以看到ap也就是arg,直接跳到可变参数列表的第一个参数.具体什么意思,学识有限
va_arg的第一个参数是arg,第二个参数是下一个参数的类型,所以每次让ap向后跳一个类型的位置
va_end 感觉没什么用,可能只是结束标志
既然是个函数,在调用过程中就要形成栈帧结构,既然要形成栈帧结构,就要知道变量的位置,如果只有 average( ... ),你传入参数,临时参数该怎么形成呢?所以,可变参数列表就必须有一个参数,这样的话根据栈帧结构,我们就可以找到后面所有参数的地址
参数列表的限制
可以看出,可变参数列表是一个参数一个参数的访问,如果你想直接访问后面的元素是做不到的,但是你想访问到中途终止,这是可行的。
因为要找到其它的参数,所以参数列表中至少有一个参数,如果连一个参数都没有,就没法初始化
宏是无法直接判断实际参数的数量的
宏无法判断每个参数的类型
如果va_arg中指定了错误的类型,那么其后果是不可预测的
函数调用:
运行结果:
C语言中,我们经常使用的printf函数,是可以输入任意多个参数的,而且当我们要写一个函数去求平均值或者其它,我们有时候要求两个数的平均值,有时候要求三个数的平均值,如果每次都封装一个函数,就很麻烦,所以C语言提供了可变参数
下面是一段求平均值的代码:
#include <stdio.h> #include <stdarg.h> int average(int n, ...) { va_list arg; int i = 0; int sum = 0; va_start(arg, n); for(i = 0; i<n; i++) { sum += va_arg(arg, int); } return sum/n; va_end(arg); }可以看到其中有几个特别的地方,va_list,va_start,va_arg,va_end
打开头文件stdarg.h
#pragma once #endif #ifndef _INC_STDARG #define _INC_STDARG #if !defined(_WIN32) #error ERROR: Only Win32 target supported! #endif #include <vadefs.h> #define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end
可以看到我们使用的va_start,va_arg等都是封装好的宏,再打开<vadefs.h>查看宏具体的实现
typedef char * va_list;
va_list就是char*,代码中我们声明一个va_list类型的变量arg,用来访问参数列表的未确定部分
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 )
va_start是用来初始化arg变量,把arg变量初始化为可变参数部分的最后一个参数,从源码中可以看到ap也就是arg,直接跳到可变参数列表的第一个参数.具体什么意思,学识有限
va_arg的第一个参数是arg,第二个参数是下一个参数的类型,所以每次让ap向后跳一个类型的位置
va_end 感觉没什么用,可能只是结束标志
既然是个函数,在调用过程中就要形成栈帧结构,既然要形成栈帧结构,就要知道变量的位置,如果只有 average( ... ),你传入参数,临时参数该怎么形成呢?所以,可变参数列表就必须有一个参数,这样的话根据栈帧结构,我们就可以找到后面所有参数的地址
参数列表的限制
可以看出,可变参数列表是一个参数一个参数的访问,如果你想直接访问后面的元素是做不到的,但是你想访问到中途终止,这是可行的。
因为要找到其它的参数,所以参数列表中至少有一个参数,如果连一个参数都没有,就没法初始化
宏是无法直接判断实际参数的数量的
宏无法判断每个参数的类型
如果va_arg中指定了错误的类型,那么其后果是不可预测的
函数调用:
int main() { printf("%d\n",average(3, 10, 15, 20)); return 0; }
运行结果:
相关文章推荐
- 【转载,必须】可变长参数列表误区与陷阱——va_end是必须的吗?
- 【C语言】可变参数列表
- 可变参数列表及printf函数的实现
- [C语言]利用可变参数列表求平均值。
- ios 可变长参数列表
- 全面解析C语言中可变参数列表
- C语言中可变参数列表解析
- 可变参数列表解析
- Pointers on C 第7章 函数——可变参数列表
- PHP可变长度参数列表的实用技巧
- python学习四:import模块方法、可变参数、字典key判断、版本信息获取、列表解析、
- c语言中参数列表可变的函数写法,如printf
- 可变参数列表(2)
- 浅析可变参数列表
- 可变参数列表浅析
- C语言可变参数列表详述及实现printf函数
- C的可变参数列表(转)
- 解析c语言中可变参数列表
- Javascript可变长度参数列表 - Arguments对象
- 可变参数列表的实现--平均值