可变参数机制并不能获取某次输入的所有参数的个数,也不能自己确定每一个输入参数的类型。看上去printf和scanf就能知道每次输入的参数个数和每个参数的类型。其实,仔细想一想就会发现printf和scanf没这个本事,输入的参数个数和每个参数的类型是使用者在format内容中,通过%模式等告诉编译器的。
va_list:一个char链表(实际上应该是一个连续的内存块,像数组一样),在使用时表现为一个指向char类型的指针;
va_start:初始化va_list。通过最后的固定参数实现对可变参数初始位置的定位,并为va_list分配内存,将可变参数复制该内存块中,使va_list指向该内存块的初始位置;
va_arg:通过移动指针va_list获取由参数Type指定的变量并返回该变量。
如下几个问题还需要特别注意一下:
1> C标准规定实现可变参数机制的函数至少要有一个固定参数。从上面的讨论可以看出,这无论是从语法上还是实现上都是必须的。
2> 隐式类型转换不可用。比如说,va_arg指定了类型是double,若传入的是int的变量10就会出错。
3> C语言的整型提升原则。也就是说,在va_arg中获取float和double使用的Type都是double,而获取char、short和int使用的Type都是int。
函数指针不可用,除非用typedef定义过。
va_list:一个char链表(实际上应该是一个连续的内存块,像数组一样),在使用时表现为一个指向char类型的指针;
va_start:初始化va_list。通过最后的固定参数实现对可变参数初始位置的定位,并为va_list分配内存,将可变参数复制该内存块中,使va_list指向该内存块的初始位置;
va_arg:通过移动指针va_list获取由参数Type指定的变量并返回该变量。
va_end:释放va_list拥有的内存块所占据的内存空间。
/*根据固定参数,输出字符串*/
#include <stdio.h>
#include <stdarg.h>
void print(int last, ...)
{
va_list ap;//typedef char* va_list
char *p;
int i = last;
va_start(ap,last);//找到第一个変参的地址 放在ap中
p = va_arg(ap, char *);//取出便惨的内容,ap指向下一変参
while(i>=1)
{
i--;
printf("%s\n", p);
p = va_arg(ap, char *);//ap 记录下一个地址,并取出当前地址的内容
//*((type)((ap += sizeof(type)))-sizeof(type)))
}
printf("\n");
va_end(ap);//释放ap指针;ap = NULL
}
int main(void)
{
print(4,"bxd", "hehe", "haha", "xixi");
print(4,"bxd", "hehe", "haha", "xixi");
// print(4,1,2,5,7);
//print(8,8,9,2,6,4,3,7,1);
// print(4,1,2,5,7);
//print(4,1,2,5,7);
print(3, "hehessssssss", "haha", "xixi");
print(1,"bxd");
return 0;
}
下面的例子实现printf的部分功能,感兴趣可以自己去完善<pre name="code" class="cpp">myprintf.c
/*实现printf的%d %c %s*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void print(char *last,...)
{
va_list ap;
char c,d;
va_start(ap, last);
while(c = *last++)
{
//实现空格输出
if(c == ' ')
{
char ch = ' ';
putchar(ch);
}
//找到%后进行取 输入的类型如%d
if(c == '%')
{
d = *last++;
switch(d)
{
case 'd':{
int h = va_arg(ap, int);
char ch = h + '0';
putchar(ch);
break;
}
case 'c':
{
char ch = va_arg(ap, int);
putchar(ch);
break;
}
case 's':
{
char *ch;
ch = (char*)malloc(sizeof(char));
ch = va_arg(ap, char *);
puts(ch);
break;
}
/*case 'p':
{
int k = 8;
int *ch = &k;
// ch = (char *)malloc(sizeof(char));
// ch = &k;
printf("%d",*ch);
// puts(&k);
// puts( (va_arg(ap, char *)));
break;
}*/
}
}
}
va_end(ap);
}
int main(void)
{
print("%d %c %s\n",3,'a',"helllo");
return 0;
}
如下几个问题还需要特别注意一下:
1> C标准规定实现可变参数机制的函数至少要有一个固定参数。从上面的讨论可以看出,这无论是从语法上还是实现上都是必须的。
2> 隐式类型转换不可用。比如说,va_arg指定了类型是double,若传入的是int的变量10就会出错。
3> C语言的整型提升原则。也就是说,在va_arg中获取float和double使用的Type都是double,而获取char、short和int使用的Type都是int。
函数指针不可用,除非用typedef定义过。