特殊函数-变参函数
定义的函数在使用时传入的参数是不定量不定类型—变参函数
include <stdarg.h>
例子:printf("abc %d def %c g\n",num,ch);
其中"abc %d def %c g\n"为固定参数,num,ch为变参列表(...)
//需要的几个宏和函数
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
其中:
va_list是用于存放参数列表的数据结构。
va_start函数根据初始化last来初始化参数列表,last为固定参数中的最后一个固定参数.(原因在后面的宏解析中)
va_arg函数用于从参数列表中取出一个参数,参数类型由type指定。
va_copy函数用于复制参数列表。
va_end函数执行清理参数列表的工作。
//如何定义一个变参函数
格式:
返回值类型 函数名(固定参数1,固定参数2,其他固定参数, ...)
{
va_list ap;//先定一个存放参数列表的数据
va_start(ap,last);//last是固定参数中最后一个参数 这里是根据最后一个参数初始化变参列表
/*中间开始根据对固定参数的处理来指定后续要拿几个变参。
每次获取参数使用va_arg(ap,type) 逐个从ap中获取变参, type是指定获取的类型 注意这里每调用一次va_arg(ap,type),都会自动指向下一个变参*/
va_end(ap);//清空参数列表
}
//应用实例
void foo(char *fmt, ...)
{
va_list ap;//1 定义 ap
int d;
char c,*s;
va_start(ap,fmt);//2 初始化ap,ap指向了变参列表
while(*fmt)//直到遇到字符串末尾的\0时结束循环
{
switch (*fmt++)
{
case 's': /* string */
s = va_arg(ap, char *);//以char*类型获取参数
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
}
va_end(ap);
}
宏解析
va_list
#ifdef _M_ALPHA
typedef struct
{
char *a0;
int offset; /* 下一个参数的字节偏移量 */
} va_list;
#else
typedef char * va_list;
#endif
//可以看出va_list就是使用一个char*类型来存储变参列表的
va_start、va_arg、va_end
//该宏的作用就是获取n所占的字节空间的大小sizeof(n)
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
//该宏的作用是为了让指针指向第一个变参的首地址,&v为获取最后一个固定参数的首地址,加上_INTSIZEOF(v)(它所占空间的字节大小),这时的指针指向最后一个固定参数的后面,即变参列表的开头,这就是为什么需要用最后一个固定参数来初始化ap。
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
//先将ap+t类型所占空间的大小,这是的ap指向下一个参数,在减去t类型所占空间的大小然后输出。
//这样就可以做到宏va_arg最后的值为当前变参的地址,而ap指向下一个变参的地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
//将ap置为0,起到删除列表的效果
#define va_end(ap) ( ap = (va_list)0 )
实例
使用变参函数实现若干整数相加问题
#include <stdio.h>
#include <stdarg.h>
int add(const int count,...)
{
va_list ap;
int n = count;
int i;
int sum = 0;
va_start(ap,count);
while(n--)
{
i = va_arg(ap,int);
sum += i;
}
va_end(ap);
return sum;
}
int main()
{
int sum = add(10,1,2,3,4,5,6,7,8,9,0);
printf("%d",sum);
return 0;
}
输出结果:45
了解了这部分内容,那么查看printf的源码就只剩下逻辑上的问题了。
>>printf源码解读
>>数据在内存中的存储
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)