1. 程式人生 > >C語言之linux核心可變參實現printf,sprintf

C語言之linux核心可變參實現printf,sprintf

      昨天,我發表了一篇用可變參實現的fprintf函式,其實說實話還不完全是可變參實現的,因為用到了FILE * 這樣的指標,需要包含stdio.h這個標頭檔案才能實現這個函式,今天我們就來看看,如何拋棄stdio.h,全0開始實現printf , sprintf ,當然,這段程式碼是我在linux核心裡面獲取的,再經過我本人修改,移植,在DevC++這個編譯環境中通過測試。我們來看看程式碼:生氣生氣

[cpp] view plain copy print?
  1. #include <stdarg.h>
  2. #define NULL 0
  3. //如果字串中為數字,則返回數字 
  4. staticint skip_atoi(
    constchar **s)  
  5. {  
  6.     int i = 0;  
  7.     while (isdigit(**s))  
  8.         i = i * 10 + *((*s)++) - '0';  
  9.     return i;  
  10. }  
  11. staticinlineint isdigit(int ch)  
  12. {  
  13.     return (ch >= '0') && (ch <= '9'); //返回從字元中提取0-9的數字
  14. }     
  15. #define ZEROPAD 1       /* pad with zero */
  16. #define SIGN    2       /* unsigned/signed long */
  17. #define PLUS    4       /* show plus */
  18. #define SPACE   8       /* space if plus */
  19. #define LEFT    16      /* left justified */
  20. #define SMALL   32      /* Must be 32 == 0x20 */
  21. #define SPECIAL 64      /* 0x */
  22. //這個巨集主要用來實現判斷是要轉化成什麼進位制數 
  23. #define __do_div(n, base) ({ \
  24. int __res; \  
  25. __res = ((unsigned long) n) % (unsigned) base; \  
  26. n = ((unsigned long) n) / (unsigned) base; \  
  27. __res; })  
  28. staticchar *number(char *str, long num, int base, int size, int precision,  
  29.             int type)  
  30. {  
  31.     /*這個字串陣列存放著0-15這16個數字,到時候要用來進位制轉換*/
  32.     staticconstchar digits[16] = "0123456789ABCDEF";   
  33.     char tmp[66];  
  34.     char c, sign, locase;  
  35.     int i;  
  36.     /*locase = 0 或者 0x20 , 產生與locase相同的數字或字母,也許字母是小寫的*/
  37.     locase = (type & SMALL);  
  38.     if (type & LEFT)  
  39.         type &= ~ZEROPAD;  
  40.     if (base < 2 || base > 36)  
  41.         return NULL;  
  42.     c = (type & ZEROPAD) ? '0' : ' ';  
  43.     sign = 0;  
  44.     if (type & SIGN) {  
  45.         if (num < 0) {  
  46.             sign = '-';  
  47.             num = -num;  
  48.             size--;  
  49.         } elseif (type & PLUS) {  
  50.             sign = '+';  
  51.             size--;  
  52.         } elseif (type & SPACE) {  
  53.             sign = ' ';  
  54.             size--;  
  55.         }  
  56.     }  
  57.     //檢測進位制數,是要2進位制還是要8進位制還是16進位制 
  58.     if (type & SPECIAL) {  
  59.         if (base == 16)  
  60.             size -= 2;  
  61.         elseif (base == 8)  
  62.             size--;  
  63.     }  
  64.     i = 0;  
  65.     if (num == 0)  
  66.         tmp[i++] = '0';  
  67.     else
  68.         while (num != 0)  
  69.             tmp[i++] = (digits[__do_div(num, base)] | locase);  
  70.     if (i > precision)  
  71.         precision = i;  
  72.     size -= precision;  
  73.     if (!(type & (ZEROPAD + LEFT)))  
  74.         while (size-- > 0)  
  75.             *str++ = ' ';  
  76.     if (sign)  
  77.         *str++ = sign;  
  78.     if (type & SPECIAL) {  
  79.         if (base == 8)  
  80.             *str++ = '0';  
  81.         elseif (base == 16) {  
  82.             *str++ = '0';  
  83.             *str++ = ('X' | locase);  
  84.         }  
  85.     }  
  86.     if (!(type & LEFT))  
  87.         while (size-- > 0)  
  88.             *str++ = c;  
  89.     while (i < precision--)  
  90.         *str++ = '0';  
  91.     while (i-- > 0)  
  92.         *str++ = tmp[i];  
  93.     while (size-- > 0)  
  94.         *str++ = ' ';  
  95.     return str;  
  96. }  
  97. int vsprintf(char *buf, constchar *fmt, va_list args)  
  98. {  
  99.     int len;  
  100.     unsigned long num;  
  101.     int i, base;  
  102.     char *str;  
  103.     constchar *s;  
  104.     int flags;        
  105.     int field_width;    /*位寬輸出*/
  106.     int precision;        
  107.     int qualifier;        
  108.     //這裡判斷,如果在字串fmt中不存在%這個符號,那麼字串繼續往後遍歷 
  109.     for (str = buf; *fmt; ++fmt) {  
  110.         if (*fmt != '%') {  
  111.             *str++ = *fmt;  
  112.             continue;  
  113.         }  
  114.         //