您的位置:首页 > 其它

可变参数列表

2017-11-10 16:10 218 查看
可变参数列表

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;
}


运行结果:

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