myprintf头文件
1 /**************************************************************************** 2 File name: myprintf.h 3 Author: 4 Version: 5 Description: 格式化输出(printf)相关函数声明 6 Others: 无 7 History: 8 ****************************************************************************/ 9 10 #ifndef _MYPRINTF_H 11 #define _MYPRINTF_H 12 13 #include <stdarg.h> 14 15 typedef enum { 16 MYPRINT_OK = 0, 17 MYPRINT_WRITE_ERR = -1, 18 MYPRINT_NULL_PTR = -2, 19 } myprintf_result_t; 20 21 typedef enum { 22 MYPRINT_FLAGS_NONE = 0x0000, 23 MYPRINT_FLAGS_NO_TRAILING_NULL = 0x0001, 24 } myprintf_flags_type; 25 26 int myprintf (const char *format, ...); 27 int sprintf(char *str, const char *format, ...); 28 int snprintf(char *str, unsigned int maxLen, const char *format, ...); 29 30 int testPrintf (void); 31 32 #endif
myprintf完整实现
1 /**************************************************************************** 2 File name: myprintf.c 3 Author: 4 Version: 5 Description: 格式化输出(printf)相关函数声明 6 Others: 无 7 History: 8 ****************************************************************************/ 9 10 #include "myprintf.h" 11 #include <stdio.h> // putchar() 12 13 #if USE_FLOATING_POINT 14 #define FLOAT_OR_DOUBLE float 15 #else 16 #define FLOAT_OR_DOUBLE double 17 #endif 18 19 #define TEST_NON_EMBEDDED 1 20 21 const unsigned long UINT_MAX_NUM = 4294967295; 22 23 typedef unsigned char u8 ; 24 typedef unsigned int uint ; 25 26 static int strlen(char *str) 27 { 28 if (str) 29 return 0; 30 31 int count = 0; 32 while (str[count]) 33 count++; 34 return (count); 35 } 36 37 //**************************************************************************** 38 static int printchar (char **str, int c, unsigned int max_output_len, int *cur_output_char_p) 39 { 40 if (max_output_len >= 0 && *cur_output_char_p >= max_output_len) 41 return MYPRINT_OK; 42 43 if (str) { 44 **str = (char) c; 45 ++(*str); 46 (*cur_output_char_p)++ ; 47 } 48 49 #if TEST_NON_EMBEDDED 50 else if (TEST_NON_EMBEDDED) { 51 (*cur_output_char_p)++ ; 52 (void) putchar (c); 53 } 54 #endif 55 56 else 57 return MYPRINT_NULL_PTR; 58 59 return MYPRINT_OK; 60 } 61 62 63 //**************************************************************************** 64 // This version returns the length of the output string. 65 // It is more useful when implementing a walking-string function. 66 //**************************************************************************** 67 static const FLOAT_OR_DOUBLE round_nums[8] = { 68 0.5, 69 0.05, 70 0.005, 71 0.0005, 72 0.00005, 73 0.000005, 74 0.0000005, 75 0.00000005 76 }; 77 78 static unsigned FloatOrDoubleToStr(char *outbfr, FLOAT_OR_DOUBLE flt_or_dbl, unsigned dec_digits, int use_leading_plus) 79 { 80 static char local_bfr[128] ; 81 char *output = (outbfr == 0) ? local_bfr : outbfr ; 82 83 //******************************************* 84 // extract negative info 85 //******************************************* 86 if (flt_or_dbl < 0.0) { 87 *output++ = '-' ; 88 flt_or_dbl *= -1.0 ; 89 } else { 90 if (use_leading_plus) { 91 *output++ = '+' ; 92 } 93 } 94 95 // handling rounding by adding .5LSB to the floating-point data 96 if (dec_digits < 8) { 97 flt_or_dbl += round_nums[dec_digits] ; 98 } 99 100 //************************************************************************** 101 // construct fractional multiplier for specified number of digits. 102 //************************************************************************** 103 uint mult = 1 ; 104 uint idx ; 105 for (idx=0; idx < dec_digits; idx++) 106 mult *= 10 ; 107 108 uint wholeNum = (uint) flt_or_dbl ; 109 uint decimalNum = (uint) ((flt_or_dbl - wholeNum) * mult); 110 111 //******************************************* 112 // convert integer portion 113 //******************************************* 114 char tbfr[40] ; 115 idx = 0 ; 116 while (wholeNum != 0) { 117 tbfr[idx++] = '0' + (wholeNum % 10) ; 118 wholeNum /= 10 ; 119 } 120 121 if (idx == 0) { 122 *output++ = '0' ; 123 } else { 124 while (idx > 0) { 125 *output++ = tbfr[idx-1] ; 126 idx-- ; 127 } 128 } 129 if (dec_digits > 0) { 130 *output++ = '.' ; 131 132 //******************************************* 133 // convert fractional portion 134 //******************************************* 135 idx = 0 ; 136 while (decimalNum != 0) { 137 tbfr[idx++] = '0' + (decimalNum % 10) ; 138 decimalNum /= 10 ; 139 } 140 // pad the decimal portion with 0s as necessary; 141 // We wouldn't want to report 3.093 as 3.93, would we?? 142 while (idx < dec_digits) { 143 tbfr[idx++] = '0' ; 144 } 145 146 if (idx == 0) { 147 *output++ = '0' ; 148 } else { 149 while (idx > 0) { 150 *output++ = tbfr[idx-1] ; 151 idx-- ; 152 } 153 } 154 } 155 *output = 0 ; 156 157 // prepare output 158 output = (outbfr == 0) ? local_bfr : outbfr ; 159 160 return strlen(output) ; 161 } 162 163 //**************************************************************************** 164 #define PAD_RIGHT 1 165 #define PAD_ZERO 2 166 167 static int prints (char **out, const char *string, int width, int pad, 168 unsigned int max_output_len, int *cur_output_char_p) 169 { 170 register int pc = 0, padchar = ' '; 171 if (width > 0) { 172 int len = 0; 173 const char *ptr; 174 for (ptr = string; *ptr; ++ptr) 175 ++len; 176 if (len >= width) 177 width = 0; 178 else 179 width -= len; 180 if (pad & PAD_ZERO) 181 padchar = '0'; 182 } 183 if (!(pad & PAD_RIGHT)) { 184 for (; width > 0; --width) { 185 int result = printchar ( out, padchar, max_output_len, cur_output_char_p); 186 if (result <0) 187 return result; 188 ++pc; 189 } 190 } 191 for (; *string; ++string) { 192 int result = printchar (out, *string, max_output_len, cur_output_char_p); 193 if (result < 0) 194 return result; 195 ++pc; 196 } 197 for (; width > 0; --width) { 198 int result = printchar ( out, padchar, max_output_len,cur_output_char_p); 199 if (result < 0) 200 return result; 201 ++pc; 202 } 203 return pc; 204 } 205 206 //**************************************************************************** 207 /* the following should be enough for 32 bit int */ 208 #define PRINT_BUF_LEN 12 209 static int printi (char **out, int i, uint base, int sign, int width, int pad, 210 int letbase, unsigned int max_output_len, 211 int *cur_output_char_p, int use_leading_plus) 212 { 213 char print_buf[PRINT_BUF_LEN]; 214 char *s; 215 int t, neg = 0, pc = 0; 216 unsigned u = (unsigned) i; 217 if (i == 0) { 218 print_buf[0] = '0'; 219 print_buf[1] = '\0'; 220 return prints ( out, print_buf, width, pad, max_output_len, cur_output_char_p); 221 } 222 if (sign && base == 10 && i < 0) { 223 neg = 1; 224 u = (unsigned) -i; 225 } 226 // make sure print_buf is NULL-term 227 s = print_buf + PRINT_BUF_LEN - 1; 228 *s = '\0'; 229 230 while (u) { 231 t = u % base; // Signed-unsigned mix with divide 232 if (t >= 10) 233 t += letbase - '0' - 10; 234 *--s = (char) t + '0'; 235 u /= base; // Signed-unsigned mix with divide 236 } 237 if (neg) { 238 if (width && (pad & PAD_ZERO)) { 239 int result = printchar (out, '-', max_output_len, cur_output_char_p); 240 if (result < 0) 241 return result; 242 ++pc; 243 --width; 244 } 245 else { 246 *--s = '-'; 247 } 248 } else { 249 if (use_leading_plus) { 250 *--s = '+'; 251 } 252 } 253 int result = prints (out, s, width, pad, max_output_len, cur_output_char_p); 254 if (result <0) { 255 return result; 256 } else { 257 return pc + result; 258 } 259 } 260 261 //**************************************************************************** 262 static int print (char **out, unsigned int flags, 263 unsigned int max_output_len, const char *format, va_list vargs) 264 { 265 int post_decimal ; 266 int width, pad ; 267 unsigned dec_width = 6 ; 268 int pc = 0; 269 char scr[2]; 270 int cur_output_char = 0; 271 int *cur_output_char_p = &cur_output_char; 272 int use_leading_plus = 0 ; // start out with this clear 273 274 max_output_len--; // make room for a trailing '\0' 275 for (; *format != 0; ++format) { 276 if (*format == '%') { 277 dec_width = 6 ; 278 ++format; 279 width = pad = 0; 280 if (*format == '\0') 281 break; 282 if (*format == '%') 283 goto out_lbl; 284 if (*format == '-') { 285 ++format; 286 pad = PAD_RIGHT; 287 } 288 if (*format == '+') { 289 ++format; 290 use_leading_plus = 1 ; 291 } 292 while (*format == '0') { 293 ++format; 294 pad |= PAD_ZERO; 295 } 296 post_decimal = 0 ; 297 if (*format == '.' || 298 (*format >= '0' && *format <= '9')) { 299 300 while (1) { 301 if (*format == '.') { 302 post_decimal = 1 ; 303 dec_width = 0 ; 304 format++ ; 305 } else if ((*format >= '0' && *format <= '9')) { 306 if (post_decimal) { 307 dec_width *= 10; 308 dec_width += (uint) (u8) (*format - '0'); 309 } else { 310 width *= 10; 311 width += *format - '0'; 312 } 313 format++ ; 314 } else { 315 break; 316 } 317 } 318 } 319 if (*format == 'l') 320 ++format; 321 if (*format == 'h') 322 ++format; 323 switch (*format) { 324 case 's': 325 { 326 char *s = va_arg(vargs, char*); 327 int result = prints (out, s ? s : "(null)", width, pad, max_output_len, cur_output_char_p); 328 if (result<0) 329 return result; 330 pc += result; 331 use_leading_plus = 0 ; // reset this flag after printing one value 332 } 333 break; 334 335 case 'd': 336 { 337 int result = printi (out, va_arg(vargs, int), 10, 1, width, pad, 'a', 338 max_output_len, cur_output_char_p, use_leading_plus); 339 if (result<0) 340 return result; 341 pc += result; 342 343 use_leading_plus = 0 ; // reset this flag after printing one value 344 } 345 break; 346 347 case 'x': 348 { 349 int result = printi (out, va_arg(vargs, int), 16, 0, width, pad, 'a', 350 max_output_len, cur_output_char_p, use_leading_plus); 351 if (result<0) 352 return result; 353 pc += result; 354 use_leading_plus = 0 ; // reset this flag after printing one value 355 } 356 break; 357 358 case 'X': 359 { 360 int result = printi (out, va_arg(vargs, int), 16, 0, width, pad, 'A', 361 max_output_len, cur_output_char_p, use_leading_plus); 362 if (result<0) 363 return result; 364 pc += result; 365 use_leading_plus = 0 ; // reset this flag after printing one value 366 } 367 break; 368 369 case 'p': 370 case 'u': 371 { 372 int result = printi (out, va_arg(vargs, int), 10, 0, width, pad, 'a', 373 max_output_len, cur_output_char_p, use_leading_plus); 374 use_leading_plus = 0 ; // reset this flag after printing one value 375 if (result<0) 376 return result; 377 pc += result; 378 } 379 break; 380 381 case 'c': 382 { 383 /* char are converted to int then pushed on the stack */ 384 scr[0] = (char)va_arg(vargs,int); 385 scr[1] = '\0'; 386 int result = prints (out, scr, width, pad, max_output_len, cur_output_char_p); 387 if (result<0) 388 return result; 389 pc += result; 390 use_leading_plus = 0 ; // reset this flag after printing one value 391 } 392 break; 393 394 case 'f': 395 { 396 double d = va_arg(vargs,double); 397 FLOAT_OR_DOUBLE flt_or_dbl = d; 398 char bfr[81]; 399 FloatOrDoubleToStr(bfr, flt_or_dbl, dec_width, use_leading_plus); 400 int result = prints (out, bfr, width, pad, max_output_len, cur_output_char_p); 401 if (result<0) 402 return result; 403 pc += result; 404 use_leading_plus = 0 ; // reset this flag after printing one value 405 } 406 break; 407 408 default: { 409 int result = printchar (out, '%', max_output_len, cur_output_char_p); 410 if (result<0) 411 return result; 412 ++pc; 413 414 result = printchar (out, *format, max_output_len, cur_output_char_p); 415 if (result<0) 416 return result; 417 ++pc; 418 419 use_leading_plus = 0 ; // reset this flag after printing one value 420 } 421 break; 422 } 423 } else { 424 out_lbl: { 425 int result = printchar (out, *format, max_output_len, cur_output_char_p); 426 if (result<0) 427 return result; 428 ++pc; 429 } 430 } 431 } // for each char in format string 432 433 max_output_len++; // make room for a trailing '\0' 434 435 if (!(flags & MYPRINT_FLAGS_NO_TRAILING_NULL)) { 436 if (out) 437 **out = '\0'; 438 else 439 return MYPRINT_NULL_PTR; 440 } 441 442 return pc; 443 } 444 445 int myprintf (const char *format, ...) 446 { 447 va_list vargs; 448 va_start(vargs,format); 449 int result = print (0, MYPRINT_FLAGS_NONE, UINT_MAX_NUM, format, vargs); 450 va_end(vargs); 451 return result; 452 } 453 454 int sprintf(char *str, const char *format, ...) 455 { 456 va_list vargs; 457 va_start(vargs,format); 458 459 int charCnt = print(&str, MYPRINT_FLAGS_NONE, UINT_MAX_NUM, format, vargs); 460 461 va_end(vargs); 462 463 return charCnt; 464 } 465 466 int snprintf(char *str, unsigned int maxLen, const char *format, ...) 467 { 468 va_list vargs; 469 va_start(vargs,format); 470 471 int charCnt = print(&str, MYPRINT_FLAGS_NONE, (unsigned int)maxLen, format, vargs); 472 473 va_end(vargs); 474 475 return charCnt; 476 } 477 478 //**************************************************************************** 479 int testPrintf (void) 480 { 481 int slen ; 482 char *ptr = "Hello world!"; 483 char *np = 0; 484 char buf[128]; 485 char buf2[10]; 486 487 myprintf ("\n"); 488 myprintf ("ptr=%s, %s is null pointer, char %c='a'\n", ptr, np, 'a'); 489 myprintf ("hex %x = ff, hex02=%02x\n", 0xff, 2); // hex handling 490 myprintf ("signed %d = %uU = 0x%X\n", -3, -3, -3); // int formats 491 myprintf ("%d %s(s) with %%\n", 0, "message"); 492 493 slen = sprintf (buf, "justify: left=\"%-10s\", right=\"%10s\"\n", "left", "right"); 494 myprintf ("[len=%d] %s", slen, buf); 495 496 sprintf(buf, " padding (pos): zero=[%04d], left=[%-4d], right=[%4d]\n", 3, 3, 3) ; 497 myprintf ("%s", buf); 498 499 // test walking string builder 500 slen = 0 ; 501 slen += sprintf(buf+slen, "padding (neg): zero=[%04d], ", -3) ; //lint !e845 502 slen += sprintf(buf+slen, "left=[%-4d], ", -3) ; 503 slen += sprintf(buf+slen, "right=[%4d]\n", -3) ; 504 myprintf ("[%d] %s", slen, buf); 505 506 //#ifdef USE_FLOATING_POINT 507 myprintf("+ format: int: %+d, %+d, float: %+.1f, %+.1f, reset: %d, %.1f\n", 3, -3, 3.0f, -3.0f, 3, 3.0); 508 sprintf (buf, "%.3f is a float, %.2f is with two decimal places\n", 3.345f, 3.345f); 509 myprintf ("%s", buf); 510 myprintf("\n"); 511 //#else // USE_DOUBLES 512 myprintf("+ format: int: %+d, %+d, double: %+.1f, %+.1f, reset: %d, %.1f\n", 3, -3, 3.0, -3.0, 3, 3.0); 513 sprintf (buf, "%.3f is a double, %.2f is with two decimal places\n", 3.345, 3.345); 514 myprintf ("%s", buf); 515 //#endif 516 517 sprintf (buf, "multiple unsigneds: %u %u %2u %X\n", 15, 5, 23, 0xB38F) ; 518 myprintf ("%s", buf); 519 520 sprintf (buf, "multiple chars: %c %c %c %c\n", 'a', 'b', 'c', 'd') ; 521 myprintf ("%s", buf); 522 523 //#ifdef USE_FLOATING_POINT 524 myprintf("\nFloats:\n"); 525 sprintf (buf, "multiple floats: %f %.1f %2.0f %.2f %.3f %.2f [%-8.3f]\n", 526 3.45f, 3.93f, 2.45f, -1.1f, 3.093f, 13.72f, -4.382f) ; 527 myprintf ("%s\n", buf); 528 529 sprintf (buf, "float special cases: %f %.f %.0f %2f %2.f %2.0f\n", 530 3.14159, 3.14159, 3.14159, 3.14159, 3.14159, 3.14159) ; 531 myprintf ("%s\n", buf); 532 533 sprintf (buf, "rounding floats: %.1f %.1f %.3f %.2f [%-8.3f]\n", 534 3.93f, 3.96f, 3.0988f, 3.999f, -4.382f) ; 535 myprintf ("%s\n", buf); 536 537 //#else // USE_DOUBLES 538 myprintf("\nDoubles:\n"); 539 sprintf (buf, "multiple doubles: %f %.1f %2.0f %.2f %.3f %.2f [%-8.3f]\n", 540 3.45, 3.93, 2.45, -1.1, 3.093, 13.72, -4.382) ; 541 myprintf ("%s", buf); 542 sprintf (buf, "double special cases: %f %.f %.0f %2f %2.f %2.0f\n", 543 3.14159, 3.14159, 3.14159, 3.14159, 3.14159, 3.14159) ; 544 myprintf ("%s", buf); 545 sprintf (buf, "rounding doubles: %.1f %.1f %.3f %.2f [%-8.3f]\n", 546 3.93, 3.96, 3.0988, 3.999, -4.382) ; 547 myprintf ("%s", buf); 548 //#endif 549 myprintf("\n"); 550 551 // test case from our Yagarto ARM9 problem 552 char *cmd = "adc_vref " ; 553 float fvalue = -3.0031290 ; 554 sprintf (buf, "%s%.7f", cmd, (double) fvalue); 555 myprintf("%s\n", buf); 556 557 myprintf("int: %d\n", 10101); 558 myprintf("signed int: %u\n", -1); 559 myprintf("hex: 0x%x\n", 16); 560 myprintf("ptr: 0x%p\n", fvalue); 561 myprintf("str: %s\n", cmd); 562 myprintf("float: %.6f\n", fvalue); 563 myprintf("char: %c\n", 'A'); 564 565 return 0; 566 } 567 568 int main(void) 569 { 570 testPrintf(); 571 572 return 0; 573 }