C语言有一个强大的功能,那就是它允许定义可接受一个可变参数列表的函数。
为了访问一个可变参量,需要使用
中的宏。他们允许在任何时候从头到尾便利一个附加参数列表,在遇到每个参数之前需要知道他的类型。
对于获取输入、输出函数就是使用的变参列表。
- stdarg.h 文件:
- #ifndef _STDARG_H //为了防止该.h文件被多次包含。
- #define _STDARG_H
- typedef char * va_list;//将va_list 定义为char*类型
- #define __va_rounded_size(TYPE) \
- (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
- #define va_start(AP, LASTARG) \
- (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
- void va_end (va_list);
- #define va_end(AP)
- #define va_arg(AP, TYPE) \
- (AP += __va_rounded_size (TYPE) , *((TYPE *) (AP - __va_rounded_size (TYPE))))
- #endif
解析:
-
__va_rounded_size(TYPE)
: 为了实现以4的倍数为基准的偏移,即TYPE =
2,通过宏之后结果为4
- va_start(AP, LASTARG)
:获取第一个变参的地址。介绍一下,对于一个变参函数参数的组成(第一个固定参数,第一个可变参数,....第n个可变参数)是对ap的初始化
- va_arg(AP, TYPE)
:遍历编参列表。使用的逗号表达式。从左开始执行,并且将最右侧的结果作为赋值结果。对于函数传递参数原则是:入栈操作,最后一个变参变量先入栈,然后根据从右到左的顺序依次入栈。
根据:C函数调用机制 了解到栈内部变量的分布情况:地址是从高到低(入栈的方向)。因此从栈底向上访问时
则需要将地址增加该变量的大小。
例子:
- #include <stdio.h>
- #include <stdarg.h>
- #define INTARG 1
- #define DBLARG 2
- void printargs(int *argtype, ...);
- int arg_types[]={INTARG,DBLARG,INTARG,DBLARG,0};
- void printargs( int*argtypep,...)
- {
- int argtype;
- va_list ap;
-
- printf("ap = %p\n",ap);
- va_start(ap,argtypep);// ap=((char*)&(argtypep)+4);
- printf("ap : %p *ap = %d \n", ap,(*(int *)ap));
- while (( argtype = *argtypep++) != 0)
- {
- switch(argtype){
- case INTARG:
- printf("ap :%p int :%d \n", ap,va_arg(ap,int));
- printf("argtypep : %p *ap = %d \n", &argtypep,(*(int *)ap));
- break;
- case DBLARG:
- printf("ap: %p double: %f \n",ap, va_arg(ap, double));
- printf("arhtypep : %p *ap = %d \n", &argtypep,(*(int *)ap));
- break;
- }
- }
- va_end(ap);
- }
- int main()
- {
- printargs(&arg_types[0], 1, 2.0, 3, 4.0);
- return 0;
- }
阅读(1383) | 评论(0) | 转发(0) |