vsprintf.c源代码

研究可变参数的时候,在网上搜到这篇源代码,放进博客慢慢学习^_^
  1. // vsprintf.c  
  2. //  
  3. // Print formatting routines  
  4. //  
  5. // Copyright (C) 2002 Michael Ringgaard. All rights reserved.  
  6. //  
  7. // Redistribution and use in source and binary forms, with or without  
  8. // modification, are permitted provided that the following conditions  
  9. // are met:  
  10. //   
  11. // 1. Redistributions of source code must retain the above copyright   
  12. //    notice, this list of conditions and the following disclaimer.    
  13. // 2. Redistributions in binary form must reproduce the above copyright  
  14. //    notice, this list of conditions and the following disclaimer in the  
  15. //    documentation and/or other materials provided with the distribution.    
  16. // 3. Neither the name of the project nor the names of its contributors  
  17. //    may be used to endorse or promote products derived from this software  
  18. //    without specific prior written permission.   
  19. //   
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND  
  21. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
  22. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
  23. // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE  
  24. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
  25. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  
  26. // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
  27. // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  
  28. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  
  29. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   
  30. // SUCH DAMAGE.  
  31. //   
  32. #include <sys/types.h>  
  33. #include <stdarg.h>  
  34. #include <string.h>  
  35. #ifdef KERNEL  
  36. #define NOFLOAT  
  37. #endif  
  38. #define ZEROPAD 1               // Pad with zero  
  39. #define SIGN    2               // Unsigned/signed long  
  40. #define PLUS    4               // Show plus  
  41. #define SPACE   8               // Space if plus  
  42. #define LEFT    16              // Left justified  
  43. #define SPECIAL 32              // 0x  
  44. #define LARGE   64              // Use 'ABCDEF' instead of 'abcdef'  
  45. #define is_digit(c) ((c) >= '0' && (c) <= '9')  
  46. static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
  47. static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  48. static size_t strnlen(const char *s, size_t count)
  49. {
  50.   const char *sc;
  51.   for (sc = s; *sc != '/0' && count--; ++sc);
  52.   return sc - s;
  53. }
  54. static int skip_atoi(const char **s)
  55. {
  56.   int i = 0;
  57.   while (is_digit(**s)) i = i*10 + *((*s)++) - '0';
  58.   return i;
  59. }
  60. static char *number(char *str, long num, int base, int size, int precision, int type)
  61. {
  62.   char c, sign, tmp[66];
  63.   char *dig = digits;
  64.   int i;
  65.   if (type & LARGE)  dig = upper_digits;
  66.   if (type & LEFT) type &= ~ZEROPAD;
  67.   if (base < 2 || base > 36) return 0;
  68.   
  69.   c = (type & ZEROPAD) ? '0' : ' ';
  70.   sign = 0;
  71.   if (type & SIGN)
  72.   {
  73.     if (num < 0)
  74.     {
  75.       sign = '-';
  76.       num = -num;
  77.       size--;
  78.     }
  79.     else if (type & PLUS)
  80.     {
  81.       sign = '+';
  82.       size--;
  83.     }
  84.     else if (type & SPACE)
  85.     {
  86.       sign = ' ';
  87.       size--;
  88.     }
  89.   }
  90.   if (type & SPECIAL)
  91.   {
  92.     if (base == 16)
  93.       size -= 2;
  94.     else if (base == 8)
  95.       size--;
  96.   }
  97.   i = 0;
  98.   if (num == 0)
  99.     tmp[i++] = '0';
  100.   else
  101.   {
  102.     while (num != 0)
  103.     {
  104.       tmp[i++] = dig[((unsigned long) num) % (unsigned) base];
  105.       num = ((unsigned long) num) / (unsigned) base;
  106.     }
  107.   }
  108.   if (i > precision) precision = i;
  109.   size -= precision;
  110.   if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
  111.   if (sign) *str++ = sign;
  112.   
  113.   if (type & SPECIAL)
  114.   {
  115.     if (base == 8)
  116.       *str++ = '0';
  117.     else if (base == 16)
  118.     {
  119.       *str++ = '0';
  120.       *str++ = digits[33];
  121.     }
  122.   }
  123.   if (!(type & LEFT)) while (size-- > 0) *str++ = c;
  124.   while (i < precision--) *str++ = '0';
  125.   while (i-- > 0) *str++ = tmp[i];
  126.   while (size-- > 0) *str++ = ' ';
  127.   return str;
  128. }
  129. static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type)
  130. {
  131.   char tmp[24];
  132.   char *dig = digits;
  133.   int i, len;
  134.   if (type & LARGE)  dig = upper_digits;
  135.   len = 0;
  136.   for (i = 0; i < 6; i++)
  137.   {
  138.     if (i != 0) tmp[len++] = ':';
  139.     tmp[len++] = dig[addr[i] >> 4];
  140.     tmp[len++] = dig[addr[i] & 0x0F];
  141.   }
  142.   if (!(type & LEFT)) while (len < size--) *str++ = ' ';
  143.   for (i = 0; i < len; ++i) *str++ = tmp[i];
  144.   while (len < size--) *str++ = ' ';
  145.   return str;
  146. }
  147. static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type)
  148. {
  149.   char tmp[24];
  150.   int i, n, len;
  151.   len = 0;
  152.   for (i = 0; i < 4; i++)
  153.   {
  154.     if (i != 0) tmp[len++] = '.';
  155.     n = addr[i];
  156.     
  157.     if (n == 0)
  158.       tmp[len++] = digits[0];
  159.     else
  160.     {
  161.       if (n >= 100) 
  162.       {
  163.         tmp[len++] = digits[n / 100];
  164.         n = n % 100;
  165.         tmp[len++] = digits[n / 10];
  166.         n = n % 10;
  167.       }
  168.       else if (n >= 10) 
  169.       {
  170.         tmp[len++] = digits[n / 10];
  171.         n = n % 10;
  172.       }
  173.       tmp[len++] = digits[n];
  174.     }
  175.   }
  176.   if (!(type & LEFT)) while (len < size--) *str++ = ' ';
  177.   for (i = 0; i < len; ++i) *str++ = tmp[i];
  178.   while (len < size--) *str++ = ' ';
  179.   return str;
  180. #ifndef NOFLOAT  
  181. char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
  182. char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf);
  183. static void cfltcvt(double value, char *buffer, char fmt, int precision)
  184. {
  185.   int decpt, sign, exp, pos;
  186.   char *digits = NULL;
  187.   char cvtbuf[80];
  188.   int capexp = 0;
  189.   int magnitude;
  190.   if (fmt == 'G' || fmt == 'E')
  191.   {
  192.     capexp = 1;
  193.     fmt += 'a' - 'A';
  194.   }
  195.   if (fmt == 'g')
  196.   {
  197.     digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf);
  198.     magnitude = decpt - 1;
  199.     if (magnitude < -4  ||  magnitude > precision - 1)
  200.     {
  201.       fmt = 'e';
  202.       precision -= 1;
  203.     }
  204.     else
  205.     {
  206.       fmt = 'f';
  207.       precision -= decpt;
  208.     }
  209.   }
  210.   if (fmt == 'e')
  211.   {
  212.     digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf);
  213.     if (sign) *buffer++ = '-';
  214.     *buffer++ = *digits;
  215.     if (precision > 0) *buffer++ = '.';
  216.     memcpy(buffer, digits + 1, precision);
  217.     buffer += precision;
  218.     *buffer++ = capexp ? 'E' : 'e';
  219.     if (decpt == 0)
  220.     {
  221.       if (value == 0.0)
  222.         exp = 0;
  223.       else
  224.         exp = -1;
  225.     }
  226.     else
  227.       exp = decpt - 1;
  228.     if (exp < 0)
  229.     {
  230.       *buffer++ = '-';
  231.       exp = -exp;
  232.     }
  233.     else
  234.       *buffer++ = '+';
  235.     buffer[2] = (exp % 10) + '0';
  236.     exp = exp / 10;
  237.     buffer[1] = (exp % 10) + '0';
  238.     exp = exp / 10;
  239.     buffer[0] = (exp % 10) + '0';
  240.     buffer += 3;
  241.   }
  242.   else if (fmt == 'f')
  243.   {
  244.     digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf);
  245.     if (sign) *buffer++ = '-';
  246.     if (*digits)
  247.     {
  248.       if (decpt <= 0)
  249.       {
  250.         *buffer++ = '0';
  251.         *buffer++ = '.';
  252.         for (pos = 0; pos < -decpt; pos++) *buffer++ = '0';
  253.         while (*digits) *buffer++ = *digits++;
  254.       }
  255.       else
  256.       {
  257.         pos = 0;
  258.         while (*digits)
  259.         {
  260.           if (pos++ == decpt) *buffer++ = '.';
  261.           *buffer++ = *digits++;
  262.         }
  263.       }
  264.     }
  265.     else
  266.     {
  267.       *buffer++ = '0';
  268.       if (precision > 0)
  269.       {
  270.         *buffer++ = '.';
  271.         for (pos = 0; pos < precision; pos++) *buffer++ = '0';
  272.       }
  273.     }
  274.   }
  275.   *buffer = '/0';
  276. }
  277. static void forcdecpt(char *buffer)
  278. {
  279.   while (*buffer)
  280.   {
  281.     if (*buffer == '.'return;
  282.     if (*buffer == 'e' || *buffer == 'E'break;
  283.     buffer++;
  284.   }
  285.   if (*buffer)
  286.   {
  287.     int n = strlen(buffer);
  288.     while (n > 0) 
  289.     {
  290.       buffer[n + 1] = buffer[n];
  291.       n--;
  292.     }
  293.     *buffer = '.';
  294.   }
  295.   else
  296.   {
  297.     *buffer++ = '.';
  298.     *buffer = '/0';
  299.   }
  300. }
  301. static void cropzeros(char *buffer)
  302. {
  303.   char *stop;
  304.   while (*buffer && *buffer != '.') buffer++;
  305.   if (*buffer++)
  306.   {
  307.     while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++;
  308.     stop = buffer--;
  309.     while (*buffer == '0') buffer--;
  310.     if (*buffer == '.') buffer--;
  311.     while (*++buffer = *stop++);
  312.   }
  313. }
  314. static char *flt(char *str, double num, int size, int precision, char fmt, int flags)
  315. {
  316.   char tmp[80];
  317.   char c, sign;
  318.   int n, i;
  319.   // Left align means no zero padding  
  320.   if (flags & LEFT) flags &= ~ZEROPAD;
  321.   // Determine padding and sign char  
  322.   c = (flags & ZEROPAD) ? '0' : ' ';
  323.   sign = 0;
  324.   if (flags & SIGN)
  325.   {
  326.     if (num < 0.0)
  327.     {
  328.       sign = '-';
  329.       num = -num;
  330.       size--;
  331.     }
  332.     else if (flags & PLUS)
  333.     {
  334.       sign = '+';
  335.       size--;
  336.     }
  337.     else if (flags & SPACE)
  338.     {
  339.       sign = ' ';
  340.       size--;
  341.     }
  342.   }
  343.   // Compute the precision value  
  344.   if (precision < 0)
  345.     precision = 6; // Default precision: 6  
  346.   else if (precision == 0 && fmt == 'g')
  347.     precision = 1; // ANSI specified  
  348.   // Convert floating point number to text  
  349.   cfltcvt(num, tmp, fmt, precision);
  350.   // '#' and precision == 0 means force a decimal point  
  351.   if ((flags & SPECIAL) && precision == 0) forcdecpt(tmp);
  352.   // 'g' format means crop zero unless '#' given  
  353.   if (fmt == 'g' && !(flags & SPECIAL)) cropzeros(tmp);
  354.   n = strlen(tmp);
  355.   // Output number with alignment and padding  
  356.   size -= n;
  357.   if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' ';
  358.   if (sign) *str++ = sign;
  359.   if (!(flags & LEFT)) while (size-- > 0) *str++ = c;
  360.   for (i = 0; i < n; i++) *str++ = tmp[i];
  361.   while (size-- > 0) *str++ = ' ';
  362.   return str;
  363. #endif  
  364. int vsprintf(char *buf, const char *fmt, va_list args)
  365. {
  366.   int len;
  367.   unsigned long num;
  368.   int i, base;
  369.   char *str;
  370.   char *s;
  371.   int flags;            // Flags to number()  
  372.   int field_width;      // Width of output field  
  373.   int precision;        // Min. # of digits for integers; max number of chars for from string  
  374.   int qualifier;        // 'h', 'l', or 'L' for integer fields  
  375.   for (str = buf; *fmt; fmt++)
  376.   {
  377.     if (*fmt != '%')
  378.     {
  379.       *str++ = *fmt;
  380.       continue;
  381.     }
  382.                   
  383.     // Process flags  
  384.     flags = 0;
  385. repeat:
  386.     fmt++; // This also skips first '%'  
  387.     switch (*fmt)
  388.     {
  389.       case '-': flags |= LEFT; goto repeat;
  390.       case '+': flags |= PLUS; goto repeat;
  391.       case ' ': flags |= SPACE; goto repeat;
  392.       case '#': flags |= SPECIAL; goto repeat;
  393.       case '0': flags |= ZEROPAD; goto repeat;
  394.     }
  395.           
  396.     // Get field width  
  397.     field_width = -1;
  398.     if (is_digit(*fmt))
  399.       field_width = skip_atoi(&fmt);
  400.     else if (*fmt == '*')
  401.     {
  402.       fmt++;
  403.       field_width = va_arg(args, int);
  404.       if (field_width < 0)
  405.       {
  406.         field_width = -field_width;
  407.         flags |= LEFT;
  408.       }
  409.     }
  410.     // Get the precision  
  411.     precision = -1;
  412.     if (*fmt == '.')
  413.     {
  414.       ++fmt;    
  415.       if (is_digit(*fmt))
  416.         precision = skip_atoi(&fmt);
  417.       else if (*fmt == '*')
  418.       {
  419.         ++fmt;
  420.         precision = va_arg(args, int);
  421.       }
  422.       if (precision < 0) precision = 0;
  423.     }
  424.     // Get the conversion qualifier  
  425.     qualifier = -1;
  426.     if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
  427.     {
  428.       qualifier = *fmt;
  429.       fmt++;
  430.     }
  431.     // Default base  
  432.     base = 10;
  433.     switch (*fmt)
  434.     {
  435.       case 'c':
  436.         if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' ';
  437.         *str++ = (unsigned char) va_arg(args, int);
  438.         while (--field_width > 0) *str++ = ' ';
  439.         continue;
  440.       case 's':
  441.         s = va_arg(args, char *);
  442.         if (!s) s = "<NULL>";
  443.         len = strnlen(s, precision);
  444.         if (!(flags & LEFT)) while (len < field_width--) *str++ = ' ';
  445.         for (i = 0; i < len; ++i) *str++ = *s++;
  446.         while (len < field_width--) *str++ = ' ';
  447.         continue;
  448.       case 'p':
  449.         if (field_width == -1)
  450.         {
  451.           field_width = 2 * sizeof(void *);
  452.           flags |= ZEROPAD;
  453.         }
  454.         str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
  455.         continue;
  456.       case 'n':
  457.         if (qualifier == 'l')
  458.         {
  459.           long *ip = va_arg(args, long *);
  460.           *ip = (str - buf);
  461.         }
  462.         else
  463.         {
  464.           int *ip = va_arg(args, int *);
  465.           *ip = (str - buf);
  466.         }
  467.         continue;
  468.       case 'A':
  469.         flags |= LARGE;
  470.       case 'a':
  471.         if (qualifier == 'l')
  472.           str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
  473.         else
  474.           str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags);
  475.         continue;
  476.       // Integer number formats - set up the flags and "break"  
  477.       case 'o':
  478.         base = 8;
  479.         break;
  480.       case 'X':
  481.         flags |= LARGE;
  482.       case 'x':
  483.         base = 16;
  484.         break;
  485.       case 'd':
  486.       case 'i':
  487.         flags |= SIGN;
  488.       case 'u':
  489.         break
  490. #ifndef NOFLOAT  
  491.       case 'E':
  492.       case 'G':
  493.       case 'e':
  494.       case 'f':
  495.       case 'g':
  496.         str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN);
  497.         continue
  498. #endif  
  499.       default:
  500.         if (*fmt != '%') *str++ = '%';
  501.         if (*fmt)
  502.           *str++ = *fmt;
  503.         else
  504.           --fmt;
  505.         continue;
  506.     }
  507.     if (qualifier == 'l')
  508.       num = va_arg(args, unsigned long);
  509.     else if (qualifier == 'h')
  510.     {
  511.       if (flags & SIGN)
  512.         num = va_arg(args, short);
  513.       else
  514.         num = va_arg(args, unsigned short);
  515.     }
  516.     else if (flags & SIGN)
  517.       num = va_arg(args, int);
  518.     else
  519.       num = va_arg(args, unsigned int);
  520.     str = number(str, num, base, field_width, precision, flags);
  521.   }
  522.   *str = '/0';
  523.   return str - buf;
  524. }
  525. int sprintf(char *buf, const char *fmt, ...)
  526. {
  527.   va_list args;
  528.   int n;
  529.   va_start(args, fmt);
  530.   n = vsprintf(buf, fmt, args);
  531.   va_end(args);
  532.   return n;
  533. }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果你要自己实现vsprintf函数而不依赖于标准库,你需要处理格式字符串中的各种格式符(如%c、%s、%d等)以及对应的参数类型。以下是一个简单的示例代码,展示了如何实现一个基本的vsprintf函数: ```c #include <stdarg.h> int vsprintf(char* str, const char* format, va_list arg) { int len = 0; // 用于记录字符串长度的变量 while (*format != '\0') { if (*format == '%') { format++; // 跳过百分号 // 处理不同的格式符 switch (*format) { case 'c': // 处理字符类型参数 { char c = (char)va_arg(arg, int); *str++ = c; len++; } break; case 's': // 处理字符串类型参数 { const char* s = va_arg(arg, const char*); while (*s != '\0') { *str++ = *s++; len++; } } break; case 'd': // 处理整数类型参数 { int num = va_arg(arg, int); int num_digits = 0; // 计算整数的位数 if (num == 0) { *str++ = '0'; len++; } else { if (num < 0) { *str++ = '-'; len++; num = -num; } int temp = num; while (temp > 0) { temp /= 10; num_digits++; } temp = num; while (num_digits > 0) { int digit = temp % 10; *str++ = '0' + digit; len++; temp /= 10; num_digits--; } } } break; // 其他格式符的处理可以根据需要进行添加 default: // 对于不支持的格式符,直接将其原样复制到结果字符串中 *str++ = *format; len++; break; } } else { // 将普通字符复制到结果字符串中 *str++ = *format; len++; } format++; // 处理下一个字符 } *str = '\0'; // 在结果字符串的末尾添加null字符 return len; // 返回结果字符串的长度 } int main() { char buffer[100]; vsprintf(buffer, "Hello, %s! The answer is %d.", "world", 42); printf("Formatted string: %s\n", buffer); return 0; } ``` 这个示例中的vsprintf函数使用了一个while循环来遍历格式化字符串,根据不同的格式符进行处理。对于%c格式符,将相应的字符复制到结果字符串中;对于%s格式符,将相应的字符串复制到结果字符串中;对于%d格式符,将相应的整数转换为字符串,并复制到结果字符串中。对于其他不支持的格式符,直接将其原样复制到结果字符串中。 希望这个示例能对你有所帮助!如果你有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值