浅析可变参数列表

来源:互联网 发布:泼墨字体生成软件 编辑:程序博客网 时间:2024/06/07 11:27
一般的函数在传参时只能传一个或两个甚至多个参数,但其前提是参数的个数必须是固定不变的。printf()函数和scanf()函数的参数却是可变的。在printf()函数中,它所传的参数是由标准化格式输出的类型决定。例:
int main(){    printf("%s\n", "hello world");    printf("%s%s%c", "hello ", "worl", 'd');    system("pause");    return 0;}
这段代码中,第一个printf有一个%s代表其参数只有一个,而第二个有三个分别是%s%s%c则代表有三个参数。两者结果相同。

这里写图片描述
对于scanf与printf相类似。
而对一般的函数要如何来做到这一点呢?下面我就来简单介绍一下可变参数列表来实现这一功能。

int average(int n, ...){    va_list arg;    //typedef char *  va_list;    int i = 0;    int sum = 0;    va_start(arg, n);    //#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )    for (i = 0; i < n; i++)    {        sum += va_arg(arg, int);        //#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )    }    return sum / n;    va_end(arg);    //#define _crt_va_end(ap)      ( ap = (va_list)0 )}int main(){    int a = 1;    int b = 2;    int c = 3;    int avg1 = average(2, a, c);    int avg2 = average(3, a, b, c);    printf("avg1 = %d\n", avg1);    printf("avg2 = %d\n", avg2);    system("pause");    return 0;}
这段代码是用来求几个数的平均值。main函数中的这两句int avg1 = average(2, a, c);int avg2 = average(3, a, b, c);中的2,3都是为后面函数在栈帧中寻找提供起始地址和控制循环次数。而average函数中:va_list arg;//typedef char *  va_list;表示arg是一个char型的指针,arg里面存的是一个地址。va_start(arg, n);//#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) );这段则表示将arg的地址赋值为位置参数列表中第一个未知参数。在函数栈帧中如图

这里写图片描述
其中intsizeof()函数的意思是向上取整。
va_arg(arg, int);
//#define _crt_va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) );即((int )((arg+=_INTSIZEOF(int))-_INTSIZEOF(int)))此时arg是一个int型指针,指向第二个未知参数,而表达式取的值是第一个未知参数的值。在函数栈帧中这样表示:
这里写图片描述
va_end(arg);
//#define _crt_va_end(ap) ( ap = (va_list)0 )
循环结束后给arg赋空指针。
在运用可变参数列表时,需要注意传n和传类型!va_arg这个表达式执行一次后就会指向下一个变量,不再是当前变量,在使用时需谨慎!可变参数列表在使用是只能从第一个挨个取直到最后一个,中间不能跳过几个变量!

原创粉丝点击