printf可变形参的研究

C语言printf函数的实现:

研究   printf 的实现,首先来看看   printf 函数的函数体
     int   printf   ( const   char   * fmt   , ...)
     {
     int   i   ;
     char   buf   [256 ];
  
     va_list   arg   = ( va_list )((   char *)(& fmt   ) + 4 );
     i   =   vsprintf   ( buf ,   fmt ,   arg   );
     write ( buf   ,   i );
  
     return   i   ;
     }
     代码位置:   D :/~/ funny   / kernel /   printf . c
  
     在形参列表里有这么一个   token ...
     这个是可变形参的一种写法。
     当传递参数的个数不确定时,就可以用这种方式来表示。
     很显然,我们需要一种方法,来让函数体可以知道具体调用时参数的个数。
  
     先来看   printf 函数的内容:
  
     这句:
  
     va_list   arg   = ( va_list )((   char *)(& fmt   ) + 4 );
  
     va_list 的定义:
     typedef   char   * va_list
     这说明它是一个字符指针。
     其中的:   ( char *)(&   fmt ) + 4)   表示的是   ... 中的第一个参数。
     如果不懂,我再慢慢的解释:
     C 语言中,参数压栈的方向是从右往左。
     也就是说,当调用   printf 函数的适合,先是最右边的参数入栈。
     fmt 是一个指针,这个指针指向第一个   const 参数( const   char   * fmt   ) 中的第一个元素。
     fmt 也是个变量,它的位置,是在栈上分配的,它也有地址。
     对于一个   char   * 类型的变量,它入栈的是指针,而不是这个   char   * 型变量。
     换句话说:
     sizeof (   p ) ( p   是一个指针,假设   p =& i   , i 为任何类型的变量都可以)
     得到的都是一个固定的值。(我的计算机中都是得到的)
     当然,我还要补充的一点是:栈是从高地址向低地址方向增长的。
     ok
     现在我想你该明白了:为什么说   ( char *)(&   fmt ) + 4)   表示的是   ... 中的第一个参数的地址。
  
     下面我们来看看下一句:
     i   =   vsprintf   ( buf ,   fmt ,   arg   );
  
     让我们来看看   vsprintf ( buf   ,   fmt ,   arg ) 是什么函数。
  
     int   vsprintf   ( char   *   buf ,   const   char   *   fmt ,   va_list   args )
     {
     char *   p   ;
     char   tmp   [256 ];
     va_list   p_next_arg   =   args ;
  
     for   ( p   = buf ;*   fmt ; fmt   ++) {
     if   (* fmt   != '%' ) {
     * p ++ = *   fmt ;
     continue ;
     }
  
     fmt ++;
  
     switch   (* fmt   ) {
     case   'x':
     itoa ( tmp   , *(( int *)   p_next_arg ));
     strcpy ( p   ,   tmp );
     p_next_arg   += 4;
     p   +=   strlen   ( tmp );
     break ;
     case   's':
     break ;
     default :
     break ;
     }
     }
  
     return   ( p   -   buf );
     }
 

本人模拟的示例:
/**
*   \brief    模拟   Printf 函数的可变形参类型的函数写法
*/
void   MyPrintf (   const   char   *   fmt ,...)
{
      //   获取“”的第一个参数的地址
      char *   arg   = ( char *)(&   fmt ) + 4;

      //   获取格式化序列的地址
      const   char   *   pStart   =   fmt ;
      char *   pStartArg   =   arg ;

      //   逐个获取格式化序列的内容
      for   (; * pStart   ;   pStart ++)
    {
          if   (* pStart   == '%' )
        {
              pStart   ++;
              char   pCurSelect   =  * pStart ;

              //   判断格式化的内容,然后输出
              switch   ( pCurSelect   )
            {
              case   'd':
                {
                      int *   pCurArg   = ( int *)   pStartArg ;
                      pStartArg   += 4;
                      cout   << * pCurArg   << endl ;
                      break ;
                }
              case   'c':
                {
                      char   * pCurArg   = ( char *)   pStartArg ;
                      pStartArg   +=4;
                      cout   << * pCurArg   << endl ;
                      break ;
                }
              default :
                  break ;
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值