Linux源码printf函数实现
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 }