首页 > 代码库 > C语言可变长参数 思考

C语言可变长参数 思考

1.我们为什么需要可变长参数

各种编程语言,如C、C++、java等都实现了可变长参数的函数。普通函数的参数个数是确定的,如果同一个函数可以接受不同数目的参数就需要适用到可变长度的参数。可变长度参数一个最典型的例子就是printf和scanf。以printf为例子,如可以有printf(“Hello Word”),printf("Hello word%s","!"),printf("Hello word%s%d","!",123)等,上面的例子中printf分别接受1,2和3个参数。当我们用程序实现计算器连加功能时,可以使用可变长参数将参数一个一个加到结果中。

2.怎么实现可变长参数

实现可变长参数功能的宏和接口封装在<stdarg.h>中。

实现可变长度将用到以下这些宏: 


void va_start( va_list arg_ptr, prev_param ); 
type va_arg( va_list arg_ptr, type ); 
void va_end( va_list arg_ptr ); 
va在这里是variable-argument(可变参数)的意思. 
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件。


实现步骤如下:

(1)声明可变长参数的函数 形式如 return_type fun_name(type1 parm1,...),"..."表示参数占位符,参数占位符在函数的最右边,而且左边至少有一个参数。如int sum(int a,...);
(2)定义可变长参数函数,定义函数用到的局部变量va_list ap;
(3)获取未知参数中的第一个参数,va_start(ap,parm1);
(4)使用循环获取所有未知的参数,var_arg(ap,type_param);
(5) 销毁va_list变量,var_end(ap);

3.可变长参数的一个实例

K&R 《The C Programming Language》中给出了minprintf-printf的简化版本。下面我将给出scanf的简化版本,minscanf(K&R书中的习题)。
自己写的代码,有不妥之处欢迎指正,代码如下:
/* Writen by samdy1990 at 1st December 2014 
   in SICT CNC lab
   reference:http://www.cnhonkerarmy.com/blog-719-654.html
*/
#include <stdio.h>

#include <stdarg.h>//must include the head file.

#define FORMATLEN 100

int miniscanf(char * format,...)
{
  va_list ap;

  va_start(ap,format);// make ap point to 1st unnamed arg 

  int *ival;
  unsigned *uval;
  double *dval;
  char *sval,*p
  int i = 0;
  char *localfmt[FORMATLEN];
   
  //loop
  for(p=format; *p;p++)//to read the format string.
  {
    if(*p != '%')
    {
      localfmt[i++] = *p;
      continue;
    }
    else
    {
      localfmt[i++] = '%';
      while(*(p+1)&&!isalpha(*(p+1)))
      {
        localfmt[i++] = *++p;
       } 
       localfmt[i++] = *(p+1);
       loaclfmt[i] = '\0';  
       switch (*++p)
       {
          case 'd':
          case 'i':
            ival = va_arg(ap,int *);
            scanf(localfmt,ival);
            break;
          case 'x':
          case 'X':
          case 'o':
          case 'u':
            uval = va_arg(ap,unsigned *);
            scanf(localfmt,uval);
            break;
          case 'g':
          case 'e':
          case 'f':
            dval = va_arg(ap,double *);
            scanf(localfmt,dval);
            break;
          case 's':
            sval = va_arg(ap,char *);
            scanf(localfmt,sval);
            break;
          default:
            scanf(localfmt);
            break;
      }
    i=0;
    }
  }
  val_end(ap);
}



C语言可变长参数 思考