va_start,va_arg,va_end,va_list应用举例--实现可变参数的函数

原创 2007年09月24日 10:43:00

/* VA.C: The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_end
 *      va_list             va_dcl (UNIX only)
 */

#include <stdio.h>
#define ANSI            /* Comment out for UNIX version     */
#ifdef ANSI             /* ANSI compatible version          */
#include <stdarg.h>
int average( int first, ... );
#else                   /* UNIX compatible version          */
#include <varargs.h>
int average( va_list );
#endif

void main( void )
{
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d/n", average( 2, 3, 4, -1 ) );

   /* Call with 4 integers. */
   printf( "Average is: %d/n", average( 5, 7, 9, 11, -1 ) );

   /* Call with just -1 terminator. */
   printf( "Average is: %d/n", average( -1 ) );
}

/* Returns the average of a variable list of integers. */
#ifdef ANSI             /* ANSI compatible version    */
int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#else       /* UNIX compatible version must use old-style definition.  */
int average( va_alist )
va_dcl
{
   int i, count, sum;
   va_list marker;

   va_start( marker );            /* Initialize variable arguments. */
   for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
      sum += i;
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#endif

Output
Average is: 3
Average is: 8
Average is: 0

 printf函数的实现比较的复杂,但是大体上是这样的。  
   
  函数用到两个比较特别的类型称之为   va_list   它主要用来访问调用函数时的参数,<其实说穿了也就是通过访问栈来实现的>  
  由于printf函数的参数是可变数目的,所以首先通过va_list变量来访问第一的参数也就是一个可以肯定的参数-字符串指针。  
   
  大概的实现我随便写写,不一定对,但是思路就是这样了。  
  int     printf(   const     char       *szFormat,...   //声明可变数目的参数   )  
  {  
          va_list         vaOldStack;  
          va_start(   vaOldStack   );   //初始化变量  
                                                             
          const   char       *szAnalysis   =   va_arg(   vaOldStack,   char   *   );  
   //存取了第一个参数,vaOldStack被更新指向下一个参数的位置  
           
          //   开始分析字符串    
          while(   szAnalysis[   i   ]   !=   '/0'   )  
          {  
                  if(   szAnalysis[   i   ]   ==   '%'   )   //   判定格式  
                  switch(   szAnalysis[   i   +   1   ]   )  
                  {  
                        case   'c':   //是要求输出字符  
                            int   ch   =   va_arg(   vaOldStack,   char   )   //从栈中取两个字节,  
               //vaOldStack被更新,指向下一个参数地址。  
                            putch(   ch   );  
                            ++i;  
                            break;  
   
                      case     'd':   //是要求输出整数  
                            int   Value   =   va_arg(   vaOldStack,   int   )//   同样取两个字节  
                            //   处理整数输出...  
                            ++i;  
                            break;  
   
                      case     'f':   //    
                      ......................  
                            以上只考虑到一小部分情况,实际还有可能要处理格式字符如  
  "%6d"   这样的。这些函数都要自己编写处理,有些比较复杂,有些简单   如处理字符输出。  
                    default:  
                        putch(szAnalysis[   i   ]   );    
                  }  
            ++i;    
        }  
          va_end(   va_list   );   //加上这句才行,因为va_start()有可能自己分配了内存需要释放。  
  }  
 

相关文章推荐

C/C++(6)va_list、va_start、va_arg、va_end实现可变参数列表函数

经典的可变参数表printf函数的实现原理:在C/C++中,对函数参数的扫描是从后向前的。 函数参数是通过压入堆栈的方式来给函数传参数的,最先压入的参数最后出来,而栈是从内存的高地址向低地址存放的,...
  • qjpxAAA
  • qjpxAAA
  • 2016年10月24日 17:40
  • 292

如何获取函数的可变参数(va_list, va_start, va_arg, va_end)

C++ prinmer 中讲到函数的可变参数(ellipsis...),但是primer中讲得比较浅,提到了怎么声明怎么调用,但是没有写明在函数内部是如何获取可变的参数的。 1)省略号(elli...

可变参数列表的函数调用 va_list va_start va_arg va_end

当无法列出函数所有形参的类型和数目时,可用省略号指定参数表,例如:            void foo(...);            void foo(parm_list,...); 下...

C语言函数之可变参数原理:va_start、va_arg及va_end !!!!!!和printascii在kernel启动前的应用

说到C语言函数可变参数,我们最先想到的可能就是printf、scanf、printk了。在Linux-2.6.24.7内核源码里,printk函数原型如下: asmlinkage int ...

《C语言接口与实现》实验——可变参数表的使用(va_list, va_start, va_arg, va_end)

《C语言接口与实现》作为接口库,源文件中大量使用了可变参数表,这些到底是怎么使用的?先来看这几个例子,基本明白了可变参数表使用。后面部分从网上整理了原理: 源程序: #include #incl...

C/C++中用va_start/va_arg/va_end实现可变参数函数的原理与实例详解

在C/C++中,我们经常会用到可变参数的函数(比如printf/snprintf等),本篇笔记旨讲解通过va_start/va_arg/va_end这簇宏来实现可变参数函数的原理,并在文末给出简单的实...
  • slvher
  • slvher
  • 2013年08月10日 17:51
  • 4967

C/C++中用va_start/va_arg/va_end实现可变参数函数的原理与实例详解 .

原文链接:http://blog.csdn.net/slvher/article/details/9881171   在C/C++中,我们经常会用到可变参数的函数(比如printf/snprintf等...

理解可变参数va_list、va_start、va_arg、va_end原理及使用方法

作者:阵利 转自:小蜜蜂的专栏   概述 由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦;即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,有些人...

深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)

一、什么是可变参数          在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为:  int printf(const char* ...

C/C++中可变参数的详细介绍(va_list,va_start,va_arg,va_end)

转自:http://www.jb51.net/article/41868.htm 可变参数的函数原理其实很简单,而va系列是以宏定义来定义的,实现跟堆栈相关.我们写一个可变函数的C函...
  • gmq_syy
  • gmq_syy
  • 2017年06月05日 17:33
  • 161
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:va_start,va_arg,va_end,va_list应用举例--实现可变参数的函数
举报原因:
原因补充:

(最多只允许输入30个字)