C语言中的可变参数编程!神奇的代码将再一次出现!

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

intprintf(constchar*format, ...);

intscanf(constchar*format, ...);

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

void va_start(va_list ap, last);

type va_arg(va_list ap, type);

void va_end(va_list ap);

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

va_list ap

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

va_start(ap, lastarg);

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

type next = va_arg(ap, type)

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

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

1 #include 

2 #include 

4 voidfunc(char*fmt, ...) 

5 { 

6       va_list ap; 

8       va_start(ap, fmt); 

10     while(*fmt)

11    {

12           switch(*fmt)

13                 {

14                    case'd':

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

16                                break;

17                    case'c':

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

19                               break;

20                    case's':

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

22                               break;

23                    default:

24                               fprintf(stderr,"error fmt\n");

25                 }

26                  fmt ++;

27       }

28       va_end(ap);

29 }

30

31 intmain (intargc,char*argv[] )

32 {

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

34     return0;

35 }/* ----------  end of function main  ---------- */

  输出结果:

10

s

hello

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

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

#defineva_list void *

 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一个一个的获取不定参数。

感谢观看!

“我自己是一名从事了10年的老程序员,辞职目前在做讲师,今年年初我花了一个月整理了一份最适合2020年学习的c++项目实战以及基础教程干货,送给每一位编程小伙伴,这里是小白聚集地,欢迎初学和进阶中的小伙伴。
官方企鹅群:720168573

编程学习推荐路线:C语言中的可变参数编程!神奇的代码将再一次出现!