您的位置:首页 > 其它

举例分析可变参数函数实现的过程

2018-03-12 21:54 309 查看
求总和函数(可变参数形式)

int average(int n,...)
{
int sum;
va_list args;
va_start(args,n);
for(int i = 0;i<n;++i)
{
sum += va_arg(args,int);
}
va_end(args);
return sum;
}


typedef char *  va_list   //为char* 别名为va_list


函数栈调用

对于C语言,其调用遵循_cdecl规则:

1.所有参数从右到左依次入栈。

2.这些参数由调用者清除,称为手动清除。

3.被调用函数不会要求调用者传递多少参数,调用者传递过多或者过少的参数,甚至完全不同的参数都不会产生编译阶段的错误。(简化的将就是调用参数的类型和数量不会产生编译阶段的错误)

以求和函数举例

int sum = sum(3,4,5,6);




三个宏宏定义

(1)va_start

#define va_start        _crt_va_start
#define _crt_va_start   va_start(ap,v)
#define va_start(ap,v)  (ap = (va_list)&v + _INTSIZEOF(v))
#define _INTSIZEOF(v) ((sizeof(v) + sizeof(int) - 1) & ~(sizeof(int)-1))


va_start宏的作用:

#define va_start(ap,v)  (ap = (va_list)&v + _INTSIZEOF(v))
ap = (char*)&v + (sizeof(v) + sizeof(int) - 1) & ~(sizeof(int)-1);


参数类型: ap为va_list类型指针,即为char *,v是最后一个确定的参数。其含义是它之后的参数均为可变参数。

功能:获取可变参数中的第一个参数,并将其地址保存在ap中。

#define _INTSIZEOF(v) ((sizeof(v) + sizeof(int) - 1) & ~(sizeof(int)-1))


_INTSIZEOF(v)宏函数是为了对齐内存。

(2)va_arg

#define va_arg(ap,t) (*(t*))(ap += _INTSIZEOF(t) - _INTSIZEOF(t))


va_arg宏的作用:

参数类型: ap为va_list类型的指针,即char,它指向当前需要获取的参数。t为当前参数的类型。

功能: 获取ap当前所指向参数的指针,并将其强制转化为 *t,并进行解引用 ,然后将ap指向可变参数表的下一个参数。

(3)va_end

#define va_end(ap)  (ap = (va_list)0)
ap = (char*)0 = NULL;


va_end宏的作用:

参数类型: ap为va_list类型的指针 。

功能: 使指针指向空,不在使用该指针。防止ap成为野指针,进行错误引用。实际上通常va_start与va_end是配对使用。

了解并掌握以上三个宏的使用方法以及函数栈调用的规则后。

下面开始分析求和可变参数函数的实现过程:

int average(int n,...)    //...表示参数的类型和数量不确定 n表示传入参数的个数
{
int sum;
va_list args;    //相当于定义   char *p;
va_start(args,n); //获取可变参数列表中的第一个参数的地址并保存在p内 va_start(p,n)
for(int i = 0;i<n;++i)
{
sum += va_arg(args,int);
}
va_end(args);   // 等价于*p = NULL;
return sum;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: