va_start,va_arg,va_end,va_list應用舉例--實現可變參數的函數

/* 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()有可能自己分配了內存需要釋放。  
  }  
 

發佈了10 篇原創文章 · 獲贊 3 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章