CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
可用分押宝游戏火热进行中... 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C语言

谁知道printf()是如何实现的?有源码吗?

楼主myc()2003-02-03 00:02:44 在 C/C++ / C语言 提问

谁知道printf()是如何实现的?有源码吗? 问题点数:100、回复次数:22Top

1 楼Caoyu015(酷鱼一代)回复于 2003-02-03 01:47:32 得分 45

很久以前研究过,现在记得不是很清楚了。  
  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()有可能自己分配了内存需要释放。  
  }  
   
   
                                       
       
             
               
   
         
           
           
   
   
   
  Top

2 楼Caoyu015(酷鱼一代)回复于 2003-02-03 01:52:35 得分 0

如果真是那么有兴趣的话可以参考一下   Andrew   Koenig的著作《   C的陷阱与  
  缺陷》上面有很详细的讨论。   我得这些东东是以前读书的时候自己研究的,  
  不知道对不对。  
  Top

3 楼myc()回复于 2003-02-03 03:00:32 得分 0

TO:   Caoyu015()  
  佩服佩服。能说说你是如何研究的吗?还有,如何深入点学C。  
  很荣幸能遇到你。Top

4 楼acange(acan)回复于 2003-02-03 04:33:19 得分 10

MiniUnix/usr/source/iolib/printf.c  
   
  char     *_ptrbf,   *_ptrst,   *__fmt;  
  printf(a1,a2,a3,a4){  
  auto   char     c,   *s,     adj,   *ptr,*p,   buf[30];  
  extern   cputc(),_putstr(),   cout;  
  auto   int     *adx,   x,   n,   m,   width,   prec,i,   padchar,   fd;  
  double   zz,   *dblptr;  
  char   (*f)();  
  _ptrbf   =   buf;  
   
  fd=cout;  
  adx   =   &a1;  
  f   =   cputc;  
  if   (a1   ==   -1)  
      {  
      f   =   _putstr;  
      _ptrst   =   a2;  
      adx   =+   2;  
      }  
  else   if   (a1   >=   0   &&   a1   <=   9)  
      fd   =   *adx++;  
  __fmt   =   *adx++;  
   
   
  while(   c   =   *__fmt++   ){  
        if(c   !=   '%')   (*f)(c,fd);  
        else   {   x   =   *adx++;  
              if(   *__fmt   ==   '-'   ){   adj   =   'l';     __fmt++;   }  
              else   adj   =   'r';  
        padchar   =   (*__fmt=='0')   ?   '0'   :   '   ';  
              width   =   __conv();  
              if(   *__fmt   ==   '.'){++__fmt;   prec   =   __conv();}  
              else   prec   =   0;  
   
        s   =   0;  
        switch   (   c   =   *__fmt++   )   {  
            case   'D':  
            case   'd':  
  _prt1(x);   break;  
            case   'o':  
            case   'O':  
                    _prnt8(x);   break;  
            case   'x':  
            case   'X':  
                      _prntx(x);   break;  
              case   'S':  
            case   's':         s=x;  
                  break;  
            case   'C':  
            case   'c':       *_ptrbf++   =   x&0777;  
                    break;  
            case   'E':  
            case   'e':  
            case   'F':  
            case   'f':  
              dblptr   =   adx-1;  
              zz   =   *dblptr;  
              adx   =+   3;  
              ftoa   (zz,   buf,   prec,   c);  
              prec   =   0;  
              s   =   buf;  
            break;  
            default:       (*f)(c,fd);  
                    adx--;  
        }  
        if   (s   ==   0)  
          {*_ptrbf   =   '\0';   s   =   buf;}  
        n   =   _clenf   (s);  
        n   =   (prec<n   &&   prec   !=   0)   ?   prec   :   n;  
        m   =   width-n;  
        if   (adj   ==   'r')   while   (m--   >   0)   (*f)(padchar,fd);  
        while   (n--)   (*f)(*s++,fd);  
        while   (m--   >   0)   (*f)(padchar,fd);  
        _ptrbf   =   buf;  
        }  
  }  
  if(a1   ==   -1)   (*f)('\0',fd);  
  }  
   
   
  _prnt8   (n)  
  {   /*   print   in   octal   */  
  int   p,   k,   sw;  
  if   (n==0)   {*_ptrbf++   =   '0';   return;}  
  sw   =   0;  
  for   (p=15;   p   >=   0;   p   =-   3)  
      if   ((k   =   (n>>p)&07)   ||   sw)  
        {  
          *_ptrbf++   =   '0'   +   k;  
            sw   =   1;  
            }  
  }  
  _prntx   (n)  
  {  
  int   d,a;  
  if   (a   =   n>>4)  
  _prntx   (   a   &   07777);  
  d   =   n&017;  
  *_ptrbf++   =     d   >   9   ?   'A'+d-10   :   '0'   +   d;  
  }  
   
  __conv()  
  {  
  auto   c,n;  
  n   =   0;  
  while(   ((c   =   *__fmt++)   >=   '0')   &&   (c<='9'))   n   =   n*10+c-'0';  
  __fmt--;  
  return(n);  
  }  
   
  _putstr(chr,str){  
  *_ptrst++   =   chr;  
  return;   ieh305i();   /*   force   loading   of   dummy.s   */  
  }  
  _prt1(n)  
  {  
  int   digs[15],   *dpt;  
  dpt   =   digs;  
  if   (n   >=   0)  
        n   =   -n;  
  else  
        *_ptrbf++   =   '-';  
  for   (;   n   !=   0;   n   =   n/10)  
    *dpt++   =   n%10;  
  if   (dpt   ==   digs)  
        *dpt++   =   0;  
  while   (dpt   !=   digs)  
        {   --dpt;  
        *_ptrbf++   =     '0'   -   *dpt;  
  }  
  }  
   
  Top

5 楼oustar(欧文)回复于 2003-02-03 09:20:10 得分 0

在《THE   C   PROGRAMMING   LANGUAGE》中有一般性的讨论。  
  GOOD   LUCK!Top

6 楼huanshilang(幻十郎)回复于 2003-02-03 13:20:53 得分 0

不错     学习一下     多谢了Top

7 楼whyNotHere(何日是尽头)回复于 2003-02-03 13:35:22 得分 0

学习中。。。Top

8 楼Caoyu015(酷鱼一代)回复于 2003-02-03 14:27:03 得分 0

大家新年好,羊年发洋财!  
   
  我个人的意见是,首先能避开C语言的陷阱写出高效CODE,这要依靠大量的上机写程序和分析原代码来作到。  
  C最强的是指针,所以C的灵魂也是指针。善于驾驭指针,你的C也就成功了一般了。《能懂汇编,结合汇编那将事半功倍》:)  
   
  接下来就要深入的就是操作系统和接口技术。   打个比喻,如果将C比喻成一根  
  如意禁箍棒,   那么这些操作系统和硬件接口技术的知识等等就是棒法.   光有好的棒子不行,还要有好的棒法.   而且你的棒法掌握的越广越精,你的如意禁锢棒也就用的越好.  
   
  以上只是我个人的妄见,听听也就算了.   ^_^      
   
   
   
   
     
   
   
  Top

9 楼cupidvenus(小鱼儿)回复于 2003-02-03 14:50:08 得分 45

#include   <stdio.h>  
  #include   <_printf.h>  
  #include   <_stdio.h>  
  int   cdecl   printf(const   char   *fmt,...)  
  {  
          return   __vprinter((putnF   *)__fputn,stdout,fmt,_va_ptr);  
  }  
  /*     而__vprinter是一个长16页的函数,需要的话给我你的邮箱     */Top

10 楼wonita(我你他)回复于 2003-02-03 15:14:09 得分 0

upTop

11 楼myc()回复于 2003-02-03 16:42:29 得分 0

TO:cupidvenus(小鱼儿)  
  谢谢。我想要__vprinter的源码,我的邮箱是my.c@163.com.麻烦你了。:)  
   
  TO:Caoyu015()    
  谢谢。能经常向你学习吗?Top

12 楼Caoyu015(酷鱼一代)回复于 2003-02-03 17:24:24 得分 0

客气!多上上csdn,上面的比我厉害的高手遍地都是。Top

13 楼swtju94_2(program)回复于 2003-02-03 18:53:23 得分 0

gzTop

14 楼myc()回复于 2003-02-03 20:38:57 得分 0

我觉得写程序,发现错误很有意义。错误能引发思考。由溢出引发的怪现象使我想知道printf()是如何实现的。printf()里面好象没有错误机制。Top

15 楼paulxj(失而复得)回复于 2003-02-03 22:02:49 得分 0

好好学习ing!!!Top

16 楼giantzz(平庸无能的政府)回复于 2003-02-03 22:48:37 得分 0

反汇编,它本身好像就是用汇编写的,反汇编应该就是看其源码  
  连main()的源码也能看!我现在就有,你要吗Top

17 楼myc()回复于 2003-02-03 23:07:12 得分 0

TO:giantzz(牛!是怎么死的。。。)    
      要啊。谢谢。my.c@163.com.Top

18 楼Caoyu015(酷鱼一代)回复于 2003-02-04 04:45:10 得分 0

在Turbo   c   2.0中看反汇编的文件的方法是:  
      进入到tc   目录下   键入   tcc   -S     文件所在目录\SourceFileName.c   既可得到   SourceFileName.asm   的汇编文件。  
   
  Turbo   c   3.0中的方法一样,bcb5.5   中的方法是   bcc32   -S   -I包含文件目录  
  -L库文件目录   SourceFileName.cpp  
   
  Top

19 楼About2Rain(山雨欲来风满楼)回复于 2003-02-04 23:32:02 得分 0

莱昂氏那本书里有Unix系统里的printf()的实现  
  基本就差不多了Top

20 楼cupidvenus(小鱼儿)回复于 2003-02-14 20:59:14 得分 0

已发给你了。Top

21 楼koeinova2002()回复于 2003-02-14 22:53:42 得分 0

能也给我一份吗?  
   
  koeinova@yahoo.com.cn  
   
  谢谢Top

22 楼caosheng(草圣)回复于 2003-02-20 17:30:14 得分 0

学习Top

相关问题

  • memcpy函数和printf函数的源码
  • asp.net怎样实现源码的保护?
  • 谁有vsscanf的实现源码?
  • 100分求C++hashmap的实现源码
  • 求string一些库实现源码
  • VS 2005如何实现源码管理?
  • 谁有java实现telnet的源码??
  • 有谁知道jspsmart的jspsmartupload的源码
  • 谁知道这网站的源码??
  • 我想画曲线,类似log曲线的样子,不知道vc里面怎样才能方便的实现,有源码最好

关键词

  • 源码
  • 函数
  • 汇编
  • 指针
  • 字符
  • 文件
  • 研究
  • ptrbf
  • vaoldstack
  • szanalysis

得分解答快速导航

  • 帖主:myc
  • Caoyu015
  • acange
  • cupidvenus

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo