変参函数的实现机制

可变参数机制并不能获取某次输入的所有参数的个数,也不能自己确定每一个输入参数的类型。看上去printf和scanf就能知道每次输入的参数个数和每个参数的类型。其实,仔细想一想就会发现printf和scanf没这个本事,输入的参数个数和每个参数的类型是使用者在format内容中,通过%模式等告诉编译器的。

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定义过。



 
 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值