可变参数列表详解

来源:互联网 发布:苹果清除app缓存数据 编辑:程序博客网 时间:2024/06/05 17:41

一、定义及表达方式

可变参数,顾名思义,其参数是可变的,具体指的是其参数的个数是可变的,即函数参数数目可变,其一般格式为:

type VarArgFunc(type FixedArg1, type FixedArg2,...)

其中,参数可分为两部分:数目固定参数和数目可变参数。函数至少需要一个固定参数,固定参数的声明和普通参数一样,可变参数由于个数不确定,声明时用“…”表示。注意,固定参数和可变参数共同构成参数列表。

二、编写可变函数准备知识

要使用可变函数,需要引入头文件 #include “stdarg.h” ,要使用可变函数,需要先认识几个宏定义:

宏定义 作用 va_list arg 定义一个指向个数可变的参数列表指针 va_start(arg,n) 使参数列表指针arg指向函数参数列表中的第一个可选参数 va_arg(arg,type) 返回参数列表中指针arg所指的参数,返回类型为type,并使指针arg指向参数列表中的下一个参数 va_end(arg) 清空参数列表,并置参数指针arg无效

下面,具体看看这几个宏定义在VS2008中的内容:

//定义一个指向个数可变的参数列表typedef  char* va_list;    //定义va_list 是一个字符指针

可以看出,va_list arg的作用等同于char* arg。

//使参数列表指针ap指向函数参数列表中的第一个可选参数#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )//其中_INTSIZEOF(v)是指如果v是1,2,3,4个字节,则返回为4,如果为5,6,7.8个字节,则返回为8,类似于整型提升的作用//v为可变参数的的前一个参数,取出该参数的地址,并对其做地址的提升,指向下一个参数(即指向第一个可变参数)

可以看出,va_start(arg,n)是使参数列表指针arg指向函数参数列表中的第一个可选参数。

//返回参数列表中指针ap所指的参数,返回类型为type,并使指针p指向参数列表中的下一个参数#define va_arg(ap,t)  (*(t *) ((ap +=_INTSIZEOF(t))-_INTSIZEOF(t)))
//清空参数列表,并置参数指针ap无效#define va_end(ap)   (ap = (va_list)0 )

三、实例说明

下面,让我们以一个求任意个参数的平均值的函数为例:

#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);    }    sum = sum/n;    va_end(arg);    return sum;}int main(){    int a = 4;    int b = 5;    int c = 7;    int avg1 = average(2, a, c);    int avg2 = average(3, a, b, c);    printf("avg1 = %d\n", avg1);    printf("avg2 = %d\n", avg2);    return 0;}

函数先出main()函数开始运行,执行到int avg1 = average(2, a, c);时调用average(int n, …),将实参2传给形参n,此时函数的栈帧如下图所示:
这里写图片描述
进入average函数后,先执行va_list arg;定义一个char*的变量arg,接着定义两个临时变量,在执行下一步:

va_start(arg, n);//这句话定义为( arg = (va_list)&n + _INTSIZEOF(n) )//取出n的地址,并使arg指向n一个下一个地址,即指向a。(此时arg指向a)

接着循环求和n次:

sum += va_arg(arg, int);//va_arg(arg, int)表示:(*(int *) ((arg +=_INTSIZEOF(int))-_INTSIZEOF(int)))//sum += (*(int *)((arg += 4)-4))//每次拿到arg所指向的内容,并使arg向下偏移一个地址,为下次取内容做准备

求和之后,将其平均值赋给sum。

va_end(arg);  //清空参数列表,并置参数指针arg无效

最后将sum返回。average函数调用完毕,完成对average函数的栈帧进行清栈。程序返回main()函数继续执行。

最后,小结一下,可变参数的函数就是:通过va_start初始化参数列表,然后使用va_arg从参数列表中取出你想要的参数,最后调用va_end执行清理工作。

4 0
原创粉丝点击