您的位置:首页 > 运维架构 > Linux

Linux源码printf函数实现

2012-09-29 16:21 232 查看
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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: