浅析可变参数列表

本文详细介绍了C语言中可变参数列表的使用方法,包括va_list、va_start、va_arg和va_end等关键宏的定义及用法。并通过一个示例程序展示了如何模拟printf函数来处理可变数量的参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可不参数列表可以让函数在不同时候接受不同数目的参数。

C语言可变参数列表使用总可分为4个部分.

 

1、va_list

首先,我们先来看一下它的定义:

#ifdef     _M_ALPHA

typedef    struct{

char*a0;/*pointertofirsthomedintegerargument*/

intoffset;/*byteoffsetofnextparameter*/

}va_list;

#else

typedef    char*va_list;#endif

就我们所知,typedefva_list定义成了一个char*类型;

所以在使用va_list时,

 

va_list arg//作用就是将arg定义成了一个char类型的指针

 

2、va_start

va_start是一个宏,它的作用是获取第一个参数的地址,即括号内的最左边第一个参数

的地址。

它的定义为:

#defineva_start(ap,v)(ap=(va_list)&v+_INTSIZEOF(v))

使ap指向第一个参数的地址。(ap即为va_list所定义的指针)

这里使用到了一个_INTSIZEOF注意,它也是一个宏,作用是获取目标参数v所占用空间的

长度大小。

它在这里起到了一个初始化的作用。具体的使用在下面会举例。

 

3va_arg

va_arg是一个宏,它的作用是向后访问。定义为:

#defineva_arg(ap,t)(*(t*)((ap+=_INTSIZEOF(t))-_INTSIZEOF(t)))

每次调用,它先获取当前的参数,并使指针ap指向下一个参数。

至于这里为什么先使ap加上一个_INTSIZEOF(t)  又减去一个_INTSIZEOF(t)从而起到是ap

指针向后移动的作用,博主尚未弄明白)。

 

4、va_end

类型也是宏,作用为清空 va_list所定义的可变参数列表。

#define  va_end(ap)  (ap=(va_list)0)


5、可变参数列表有几个限制条件

<1>  函数的参数至少含有一个。

<2>  va_start无法计算参数的个数。

<3>  无法直接知道参数类型。

<4>  va_arg如果给定了错误的类型,结果不可预料。


下面来看一个例子

// 利用可变参数列表模拟printf函数输出字符串,字符。 
#include<stdio.h>
#include<stdarg.h>
 void print(const char *format,...)
  {
  	va_list arg;
	  //定义arg(char类型)指针 
  	va_start(arg,format);
	  //对arg进行初始化,使其指向第一个参数 
  	while(*format)
  	  {
  	    switch(*format)
		  //因为有字符,字符串两种情况,所以这里用switch比较好。 
  	     {
		   
		  case's':
		  	//若读取到为s,则为字符串 
		  	{
		  	char *str=va_arg(arg,char*);
			  /*注意,这里要用一个局部变量对va_arg(arg,char*)进行一次保存,
			  因为每次调用一次va_arg(arg,char*),它都会向后移动, 若,直接
			  puts(va_arg(arg,char*))会输出下一个参数的值。*/ 
		  	 puts(str);
		    }
		    break;	
		  case'c':
		  	//若为猜,则为字符。 
		  	{
		  	char tmp=va_arg(arg,char);//若此处char不行,换用int 试一下。博主遇到过这种情况,尚未明白。 
		  	//同样用tmp进行一次保存。 
			 /*注意,va_arg不会辨别参数的类型,该参数是什么类型,va_arg括号中
			 第二个位置就写什么类型,不要写错,不热会造成不可预料的后果。这也是
			 可变参数列表的一个限制条件。*/ 
		  	 putchar(tmp);
		  }
		  	break;
		  
		  default:
		  	/*当switch所有情况列举完后,用default分支结尾。即使真的不需要default,
			  也应该保留语句 ,具体作用自己网查*/ 
		  	 putchar(*format);
		  	 break;
		  }
		format++;
	  }
	va_end(arg);//最后清空va_list定义的arg
	 
  	
  }
 int main()
  {
  	print("s ccc.\n","hello",'b','i','t');
  	return 0;
   } 

执行后结果应为:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值