变长参数列表函数

可变参数列表


头文件<stdarg.h>提供了遍历未知数目和类型的函数参数表的功能。该头文件的实现因不同的机器而不同,但提供的接口是一致的。
假定函数 f 带有可变数目的实际参数,lastarg 是它的最后一个命名的形式参数(参数列表必须至少包括一个命名参数)。那么,在函数 f 内声明一个类型为 va_list 的变量 ap (argument pointer),它将依次指向每个实际参数。

 

va_list ap ;


在访问任何未命名的参数前,必须用 va_start 宏初始化 ap 一次。(va_start 将最后一个命名参数作为起点,将 ap 初始化为指向第一个未命名参数的指针)

va_start (va_list ap , lastarg ) ;

此后,每次执行宏 va_arg 都将返回一个参数,并将 ap 指向下一个参数。 va_arg 使用一个类型名来决定返回的对象类型、指针移动的步长。

Type  va_arg (va_list ap , Type ) ;

在所有的参数处理完毕之后,且在退出函数 f 之前,必须调用宏 va_end 以完成一些必要的清理工作。

void  va_end (va_list ap ) ;

Example


下面以实现函数printf的一个最简单版本为例,介绍如何以可移植的方式编写可处理变长参数列表的函数。因为我们的重点在于参数的处理,所以,函数minprintf只处理格式字符串和参数,格式转换则通过调用函数printf实现。
函数printf的正确声明形式为:

 

int  printf ( char  *fmt , ... )

其中,省略号表示参数表中参数的数量和类型是可变的。省略号只能出现在参数表的尾部。
因为minprintf函数不需要像printf函数一样返回实际输出的字符数,因此,我们将它声明为下列形式:

void minprintf ( char  *fmt , ... )

编写函数minprintf的关键在于如何处理一个甚至连名字都没有的参数表。

#include <stdio.h>
#include <stdarg.h>

/* minprintf 函数:带有可变参数表的简化的printf函数 */
void minprintf ( char  *fmt , ... )
{
    va_list ap ;   /* 依次指向每个无名参数 */
     char  *p ,  *sval ;
     int ival ;
     double dval ;

     va_start (ap , fmt ) ;   /* 将 ap 指向第一个无名参数 */
     for  (= fmt ;  *p ; p ++ )  {
         if  ( *!=  '%' )  {
             putchar ( *p ) ;
             continue ;
         }
         switch  ( *++p )  {
             case  'd' :
                ival  =  va_arg (ap ,  int ) ;
                 printf ( "%d" , ival ) ;
                 break ;
             case  'f' :
                dval  =  va_arg (ap ,  double ) ;
                 printf ( "%f" , dval ) ;
                 break ;
             case  's' :
                 for  (sval  =  va_arg (ap ,  char  * ) ;  *sval ; sval ++ )
  putchar ( * sval ) ;
                 break ;
             default :
                 putchar ( * p ) ;
                 break ;
         }
     }
     va_end ( ap ) ;   /* 结束时的清理工作 */
}

你可能感兴趣的:(函数)