c#发展

注册

 

发新话题 回复该主题

青鸟飞扬C语言中的可变参数编程 [复制链接]

1#

在c语言中使用变长参数最常见的就是下面两个函数了:

intprintf(constchar*format,...);

intscanf(constchar*format,...);

 那他们是怎样实现支持变成参数的呢?在使用变长参数的函数(这里假设是func)实现部分其实用到了stdarg.h里面的多个宏来访问那些不确定的参数,它们分别是:

voidva_start(va_listap,last);

typeva_arg(va_listap,type);

voidva_end(va_listap);

 假设lastarg是func的最后一个具名参数,即在func函数定义中...之前的那个参数(在printf中lastarg是format),在func中首先定义一个变量:

va_listap

 这个变量以后会依次指向各个可变参数。ap在使用之前必须用宏va_start初始化一次,如下所示:

va_start(ap,lastarg);

其中lastarg是func中的最后一个具名参数。然后就可以用va_arg来获得下一个不定参数(前提是知道这个不定参数的类型type):

typenext=va_arg(ap,type)


  最后就是用宏va_end来清理现场。


  下面我们来自己实现一个可变参数的函数:

1#include

2#include

3

4voidfunc(char*fmt,...)

5{

6va_listap;

7

8va_start(ap,fmt);

9

10while(*fmt)

11{

12switch(*fmt)

13{

14cased/p>

15fprintf(stdout,"%d\n",(int)va_arg(ap,int));

16break;

17casec/p>

18fprintf(stdout,"%c\n",(char)va_arg(ap,int));

19break;

20cases/p>

21fprintf(stdout,"%s\n",(char*)va_arg(ap,char*));

22break;

23default/p>

24fprintf(stderr,"errorfmt\n");

25}

26fmt++;

27}

28va_end(ap);

29}

30

31intmain(intargc,char*argv[])

32{

33func("dcs",10,s,"hello");

34return0;

35}/*----------endoffunctionmain----------*/


  输出结果:

10

s

hello


  可以看到上面的程序完成按我们的意愿实现了变长参数的访问,通过前面的fmt来控制下一个不定参数的类型。那这三个宏是怎样实现对不定参数访问的呢?下面来看看它们是怎么实现的:


  va_list实际就是一个指向各个不定参数的指针,由于参数的类型是不确定的,所以可以定义va_list为void*或者char*类型,即

#defineva_listvoid*

 va_start就是将va_list指向函数最后一个具名参数lastarg后面的位置,这个位置就是第一个不定参数。

#defineva_start

(ap,lastarg)\(ap=(va_list)lastarg+sizeof(lastarg))

 va_arg获取当前不定参数的值,根据当前参数的类型的大小移动指针指向下一个不定参数。

#defineva_arg(ap,type)\

(*(type*)((ap+=sizeof(type))-sizeof(type)))


  va_end将指针清0。

#defineva_end(ap)(ap=(va_list)0)


  本质上其实就是靠前面lastarg来控制不定参数的类型,va_list变量来指向不定参数的地址,然后根据lastarg一个一个的获取不定参数。

分享 转发
TOP
发新话题 回复该主题