C語言之linux核心可變參實現printf,sprintf
阿新 • • 發佈:2019-02-06
昨天,我發表了一篇用可變參實現的fprintf函式,其實說實話還不完全是可變參實現的,因為用到了FILE * 這樣的指標,需要包含stdio.h這個標頭檔案才能實現這個函式,今天我們就來看看,如何拋棄stdio.h,全0開始實現printf , sprintf ,當然,這段程式碼是我在linux核心裡面獲取的,再經過我本人修改,移植,在DevC++這個編譯環境中通過測試。我們來看看程式碼:
[cpp] view plain copy print?- #include <stdarg.h>
- #define NULL 0
- //如果字串中為數字,則返回數字
- staticint skip_atoi(
- {
- int i = 0;
- while (isdigit(**s))
- i = i * 10 + *((*s)++) - '0';
- return i;
- }
- staticinlineint isdigit(int ch)
- {
- return (ch >= '0') && (ch <= '9'); //返回從字元中提取0-9的數字
- }
- #define ZEROPAD 1 /* pad with zero */
- #define SIGN 2 /* unsigned/signed long */
- #define PLUS 4 /* show plus */
- #define SPACE 8 /* space if plus */
- #define LEFT 16 /* left justified */
- #define SMALL 32 /* Must be 32 == 0x20 */
- #define SPECIAL 64 /* 0x */
- //這個巨集主要用來實現判斷是要轉化成什麼進位制數
- #define __do_div(n, base) ({ \
- int __res; \
- __res = ((unsigned long) n) % (unsigned) base; \
- n = ((unsigned long) n) / (unsigned) base; \
- __res; })
- staticchar *number(char *str, long num, int base, int size, int precision,
- int type)
- {
- /*這個字串陣列存放著0-15這16個數字,到時候要用來進位制轉換*/
- staticconstchar digits[16] = "0123456789ABCDEF";
- char tmp[66];
- char c, sign, locase;
- int i;
- /*locase = 0 或者 0x20 , 產生與locase相同的數字或字母,也許字母是小寫的*/
- locase = (type & SMALL);
- if (type & LEFT)
- type &= ~ZEROPAD;
- if (base < 2 || base > 36)
- return NULL;
- c = (type & ZEROPAD) ? '0' : ' ';
- sign = 0;
- if (type & SIGN) {
- if (num < 0) {
- sign = '-';
- num = -num;
- size--;
- } elseif (type & PLUS) {
- sign = '+';
- size--;
- } elseif (type & SPACE) {
- sign = ' ';
- size--;
- }
- }
- //檢測進位制數,是要2進位制還是要8進位制還是16進位制
- if (type & SPECIAL) {
- if (base == 16)
- size -= 2;
- elseif (base == 8)
- size--;
- }
- i = 0;
- if (num == 0)
- tmp[i++] = '0';
- else
- while (num != 0)
- tmp[i++] = (digits[__do_div(num, base)] | locase);
- if (i > precision)
- precision = i;
- size -= precision;
- if (!(type & (ZEROPAD + LEFT)))
- while (size-- > 0)
- *str++ = ' ';
- if (sign)
- *str++ = sign;
- if (type & SPECIAL) {
- if (base == 8)
- *str++ = '0';
- elseif (base == 16) {
- *str++ = '0';
- *str++ = ('X' | locase);
- }
- }
- if (!(type & LEFT))
- while (size-- > 0)
- *str++ = c;
- while (i < precision--)
- *str++ = '0';
- while (i-- > 0)
- *str++ = tmp[i];
- while (size-- > 0)
- *str++ = ' ';
- return str;
- }
- int vsprintf(char *buf, constchar *fmt, va_list args)
- {
- int len;
- unsigned long num;
- int i, base;
- char *str;
- constchar *s;
- int flags;
- int field_width; /*位寬輸出*/
- int precision;
- int qualifier;
- //這裡判斷,如果在字串fmt中不存在%這個符號,那麼字串繼續往後遍歷
- for (str = buf; *fmt; ++fmt) {
- if (*fmt != '%') {
- *str++ = *fmt;
- continue;
- }
- //