可变参数列表源码的解析

来源:互联网 发布:php注册短信代码 编辑:程序博客网 时间:2024/06/04 20:02

C语言中的可变参数是一个比较有意思的实现,一旦将某个函数组装成参数可变的函数,它可以接受任意多个参数。从定义中我们不难体会到常用的printf 和 scanf等函数是这类函数,感谢我们的前辈,他们已实现的函数给我们带来了极大的便利。下面谈谈我对可变参数的理解,首先写一个参数可变的函数(实现求几个数的平均值)。
#include<stdio.h>#include<windows.h>#include<stdarg.h>int average(int nums,...){
int sum = 0;va_list arg;va_start(arg,nums);while(nums--){sum += va_arg(arg,int);}return sum/nums;
va_end(NULL);}int main(){printf("ave1 = %d\n",average(2,10,20));printf("ave2 = %d\n",average(2,10,20,30));system("pause");return 0;}
读懂和深度理解这个程序的关键是对va_list,va_tast,va_arg,va_end这四个新朋友的功能理解,我们欢迎他们,下面我给大家介绍这四个朋友:
va_list arg:这个很好理解,它相当于 char *arg ,相信说到这里对这个不许过多解释。
va_tast(arg,nums):说直白点这里实现了一个初始化,它实现的功能是将 arg 指向未知的第一个参数; 这里对很多朋友可能有点误导,很可能会理解成此处 nums 处的对象是从左至右参数部分的第一个参数,这里并不是这样,这里的对象应该是在参数中从左至右离 ... 最近的那个参数。这句代码的汇编是 ap = (va_last)&v + _INTSIZEOF(v) ( ap 相当于此处的 arg , v 相当于此处的 nums ),_INTSIZEOF(v) 实现整形提升,即就是当 v 所代表的类型所占的字节是 1,2,3,4 时, _INTSIZEOF(v)的值为 4 ,当 v 所代表的类型所占的字节是 5,6,7,8 时, _
INTSIZEOF(v) 的值是 8 ,结合形参实例化的过程从这句汇编容易理解为什么 ap 指向的第一个是未知参数,至于为什么要进行整形提升此处不作解释,有能力的朋友评论做个解释,分享给大家,谢谢。
va_ arg(arg,int):此表达式是可变参数函数实现的核心,它即实现了取当前 arg 所指向的对象实体,又实现了将 arg 指向下一个参数的功能。这句代码的汇编是 *(t *)((ap += _INTSIZEOF(t)) - _INTsizeof(t)) ( t 相当于此处的 int ,代表相对应的参数的类型,一个函数中可以有 int char 等等),不难发现 ap += _INTSIZEOF(t) 实现了将 ap 指向下一个参数, (t*)((ap += _INTSIZEOF(t)) - _INTsizeof(t)) 实现了取当前 ap 所指向的那个值。这个操作真的真的是厉害炸了。
va_end(NULL):我觉得这里体现出了我们程序员的职业性,就是最后将 ap 赋成NULL。 
最后感谢各位的阅读,我是一个初学者,错误难免,有问题或者解释不明的请朋友们评论交流。谢谢各位