C常用头文件

stdarg.h

stdarg.h 头文件定义了一个变量类型 va_list 和三个宏,这三个宏可以用于在参数个数未知(即参数个数可变)是获取函数的参数;

拥有可变参数的函数通过在参数列表的末尾使用省略号(,...)来定义,如下:

int check(int a, double b, ...);

不定参数的函数至少要有一个命名参数,所以下面的定义在C语言中是不允许的 :

char *wrong(...);

库变量 va_list

va_list是一个char类型的指针,当被调用函数使用一个可变参数时,用它声明一个类型为va_list的变量,该变量用来指向va_arg和va_end所需信息的位置;下面给出va_list在C中的源码:

typedef char *  va_list;

库宏

void va_start(va_list ap, last_arg);

这是一个带参数的宏,它使va_list类型变量ap指向被传递给函数的可变参数表中的第一个参数,在第一次调用va_arg和va_end之前,必须首先调用该宏

va_start的第二个参数 last_arg 是传递给被调用函数的最后一个固定参数,,即省略号前面的参数;

va_start使ap只指向lastfix之外的可变参数表中的第一个参数,很明显它先得到第一个参数内存地址,然后又加上这个参数的内存大小,就是下个参数的内存地址了 ;

下面给出va_start在C中的源码:

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )   //得到可变参数中第一个参数的首地址

type va_arg(va_list ap, type);

ap 是一个 va_list 类型的对象,存储了有关额外参数和检索状态的信息,该对象第一次调用应该是在 va_arg之前 通过调用 va_start 进行初始化;

type 是一个类型名称,作为扩展自该宏的表达式的类型来使用;

这个宏使用有双重目的:第一个是返回ap所指对象的值,第二个是修改参数指针ap使其增加以指向表中下一个参数。va_arg的第二个参数提供了修改参数指针所必需的信息。在第一次使用va_arg时,它返回可变参数表中的第一个参数,如上面的10,后续的调用都返回表中的下一个参数,如上面的20和30,这些参数的类型为 type 类型;下面给出va_arg在C中的源码:

#define va_arg(ap,type)    ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )    //将参数转换成需要的类型,并使ap指向下一个参数

在使用va_arg时,要注意第二个参数所用类型名应与传递到堆栈的参数的字节数对应,以保证能对不同类型的可变参数进行正确地寻址,比如实参依次为char型、char* 型、int型和float型时,在va_arg中它们的类型则应分别为int、char *、int和double;

void var_end(va_list ap);

ap 是之前由同一个函数中的 va_start 初始化的 va_list 对象;该宏用于被调用函数完成正常返回,功能就是把指针ap赋值为0,使它不指向内存的变量;下面给出va_end在C中的源码:

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

下面来看 printf 函数的实现原理:

printf的函数原型为:

int printf(const char * format, ... );

printf的实现远比上面的sum函数复杂。sum函数之所以看起来简单,是因为:

  • sum函数可变参数表的长度是已知的,通过num_arg参数传入;
  • sum函数可变参数表中参数的类型是已知的,都为int型;

而printf函数则没有这么幸运。首先,printf函数可变参数的个数不能轻易的得到,而可变参数的类型也不是固定的,需由格式字符串进行识别(由%f、%d、%s等确定),因此则涉及到可变参数表的更复杂应用;

在printf中,需通过对传入的格式控制字符串进行识别来获知可变参数个数及各个可变参数的类型,具体实现体现在for循环中;譬如,在识别为%d后,做的是va_arg ( vap, int ),而获知为%l和%lf后则进行的是va_arg ( vap, long )、va_arg ( vap, double )。格式字符串识别完成后,可变参数也就处理完了;

猜你喜欢

转载自blog.csdn.net/bleauchat/article/details/117387343