Linux源码printf函数实现

时间:2023-01-19 19:24:03

Linux源码printf函数实现


  1 #include<io.h>
  2 #include<ctype.h>
  3 #include<string.h>
  4 #include<stdio.h>
  5 typedef char *va_list;
  6 #define va_round_size(TYPE) (((sizeof(TYPE)+sizeof(int)-1)/sizeof(int))*sizeof(int)) //4的整数倍
  7 #define va_start(AP,LASTARG) (AP=((char *)&(LASTARG)+va_round_size(LASTARG)))
  8 #define va_arg(AP,TYPE) (AP+=va_round_size(TYPE),*((TYPE*)(AP-va_round_size(TYPE))))//得到可变参数的地址,第一次返回时得到第一个参数的地址
  9 #define va_end(AP)//将释放参数表AP
 10 #define ZEROPAD 1
 11 #define PLUS 4
 12 #define SPACE 8
 13 #define LEFT 16
 14 #define SPECIAL 32
 15 #define STDOUT 1
 16 #define SMALL 64
 17 #define SIGN  2
 18 static int getFieldWidth(char **str);
 19 static char printbuf[1024];
 20 static char *number(char *str,int num,int base,int size,int precision,int type);
 21 int vsprintf(char *buf,const char *fmt,va_list args);
 22 static int println(const char *fmt,...);
 23 int __res=0;
 24 //进制之间的相应转换
 25 #define do_div(n,base)  (\
 26     __res=((unsigned long)n)%(unsigned)base,\
 27     n=((unsigned long)n)/(unsigned)base,\
 28     __res\
 29 )
 30 /*测试printf函数*/
 31 int main()
 32 {
 33     int tmp=10;
 34     println("%p\n",tmp);
 35     return 0;
 36 }
 37 /*
 38     获取显示宽度
 39 */
 40 int getFieldWidth(const char **str)
 41 {
 42     int len=0;
 43     while(isdigit(**str))
 44         len=len*10+*((*str)++)-'0';
 45     return len ;
 46 }
 47 /*
 48     以特定的进制格式化输出字符
 49 */
 50 static char *number(char *str,int num,int base,int size,int precision,int type)
 51 {
 52     char c,sign,tmp[36];
 53     const char *digits="0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZ";
 54     int i;
 55     if(type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
 56     if(type&LEFT) type&=~ZEROPAD;
 57     if(base<2||base>36)
 58         return 0;
 59     c=(type&ZEROPAD)?'0':' ';
 60     if(type&SIGN&&num<0){
 61         sign='-';
 62         num=-num;
 63     }
 64     else
 65         sign=(type&PLUS)?'+':((type&SPACE)?' ':0);
 66     if(sign)
 67         size--;
 68     if(type&SPECIAL)
 69         if(type==16)
 70             size-=2;
 71         else if(base==8)
 72             size--;
 73     i=0;
 74     if(num==0)
 75         tmp[i++]='0';
 76     else
 77         while(num!=0)
 78             tmp[i++]=digits[do_div(num,base)];
 79     if(i>precision)
 80         precision=i;
 81     size=-precision;
 82     if(!(type&(ZEROPAD+LEFT)))
 83         while(size-->0)
 84             *str++=' ';
 85     if(sign)
 86         *str++=sign;
 87     if(type&SPECIAL)
 88         if(base==8)
 89             *str++='0';
 90         else if(base==16)
 91         {
 92             *str++='o';
 93             *str++=digits[33];
 94         }
 95     if(!(type&LEFT))
 96         while(size-->0)
 97             *str++=c;
 98     while(i<precision--)
 99         *str++='0';
100     while(i-->0)
101         *str++=tmp[i];
102     while(size-->0)
103         *str++=' ';
104     return str;
105 }
106 /*
107     打印输出函数
108 */
109 int vsprintf(char *buf,const char *fmt,va_list args)
110 {
111     int len,i,*ip,flags,field_width,precision,qualifier;
112     char *str,*s;
113     for(str=buf;*fmt;++fmt)
114     {
115         if(*fmt!='%')
116         {
117             *str++=*fmt;
118             continue;
119         }
120         /*处理相关的标记*/
121         flags=0;
122 repeat:
123         ++fmt; //跳过第一个%号
124         switch(*fmt)
125         {    
126         case '-':
127                 flags|=LEFT;
128                 goto repeat;
129         case '+':
130                 flags|=PLUS;
131                 goto repeat;
132         case ' ':
133                 flags|=SPACE;
134                 goto repeat;
135         case '#':
136                 flags|=SPECIAL;
137                 goto repeat;
138         case '0':
139                 flags|=ZEROPAD;
140                 goto repeat;
141         }
142         field_width=-1;
143         if(isdigit(*fmt))
144             field_width=getFieldWidth(&fmt);//获取域宽
145         precision=-1;//获取精度
146         if(*fmt=='.')
147         {
148             ++fmt;
149             if(isdigit(*fmt))
150                 precision=getFieldWidth(&fmt);
151             if(precision<0)
152                 precision=0;
153         }
154         qualifier=-1;//获取相应的修饰符
155         if(*fmt=='H'||*fmt=='L'||*fmt=='l')
156         {
157             qualifier=*fmt;
158             ++fmt;
159         }
160         switch(*fmt)//判断相应的格式串
161         {
162         case 'c':
163             if(!(flags&LEFT))
164                 while(--field_width>0)
165                     *str++=' ';
166             *str++=(unsigned char)va_arg(args,int);//将参数值存入printbuf里的
167             while(--field_width>0)
168                 *str++=' ';
169             break;
170         case 's':
171             s=va_arg(args,char *);
172             len=strlen(s);
173             if(precision<0)
174                 precision=len;
175             else if(len>precision)
176                 len=precision;
177             if(!(flags&LEFT))
178                 while(len<field_width--)
179                     *str++=' ';
180             for(i=0;i<len;++i)
181                 *str++=*s++;
182             while(len<field_width--)
183                 *str++=' ';
184             break;
185         case 'o':
186             str=number(str,va_arg(args,unsigned long),8,field_width,precision,flags);
187             break;
188         case 'p':
189             if(field_width==-1){
190                 field_width=0;
191                 flags|=ZEROPAD;
192             }
193             str=number(str,(unsigned long)va_arg(args,void *),16,field_width,precision,flags);
194             break;
195         case 'x':
196             flags|=SMALL;
197         case 'X':
198             str=number(str,va_arg(args,unsigned long),16,field_width,precision,flags);
199             break;
200         case 'd':
201         case 'i':
202             flags|=SIGN;
203         case 'u':
204             str=number(str,va_arg(args,unsigned long),10,field_width,precision,flags);
205             break;
206         case 'n':
207             ip=va_arg(args,int *);
208             *ip=(str-buf);
209             break;
210         default:
211             if(*fmt!='%')
212                 *str++='%';
213             if(*fmt)
214                 *str++=*fmt;
215             else
216                 --fmt;
217             break;
218         }
219     }
220     *str='\0';
221     return str-buf;
222 }
223 /*可变函数在内部实现的过程中是从右向左压入堆栈,从而保证了可变参数的第一个参数始终位于栈顶*/
224 static int println(const char *fmt,...)
225 {
226     va_list args;//定义一个char类型的指针
227     int i;
228     va_start(args,fmt);//实际上可以理解为(char *)&fmt+4指向了第一个参数,(char *)&fmt+8指向了第二个参数
229     write(STDOUT,printbuf,i=vsprintf(printbuf,fmt,args));//将printbuf里的值写入标准输出
230     va_end(args);//关闭函数参数列表,将参数置空(即args=NULL)
231     return i;
232 }