首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言可變參數函數 myprintf 實作詳解:補全 x/o/% 格式化

     編輯:程式設計綜合問答

原始碼架構

int myprintf(const char *format, ...) {
    va_list ap;
    int data;
    char str[32] = {0};
    char *p;

    va_start(ap, format);
    while (*format != '\0') {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 'x': /* TODO: 十六進制 */ break;
                case 'o': /* TODO: 八進制 */ break;
                case '%': /* TODO: 輸出 % 本身 */ break;
                case 's': p = va_arg(ap, char *); myputs(p); break;
                case 'd': data = va_arg(ap, int); str[0] = '\0'; itoa(data, str); myputs(str); break;
                case 'c': data = va_arg(ap, int); putchar(data); break;
            }
        } else {
            putchar(*format);
        }
        format++;
    }
    va_end(ap);
}

補全三個 case

case 'x': 
    data = va_arg(ap, int);
    str[0] = '\0';
    // itoa 不支援基數 16,自寫或用 sprintf
    sprintf(str, "%x", data); 
    myputs(str);
    break;

case 'o':
    data = va_arg(ap, int);
    str[0] = '\0';
    sprintf(str, "%o", data);
    myputs(str);
    break;

case '%':
    putchar('%');
    break;

關鍵知識點

  1. va_arg 取參順序:必須與格式字串對應,%x/%o 取 int。
  2. itoa 非標準:C 標準庫無 itoa,建議用 sprintf 或自寫 utoa。
  3. % 處理:格式字串 %% 輸出單個 %,故 case '%' 直接 putchar('%')。
  4. 緩衝區大小:char str[32] 足夠容納 32 位整數的八/十六進制(最多 11 字元含結束符)。

完整可編譯版本

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

void myputs(const char *s) { while (*s) putchar(*s++); }

int myprintf(const char *format, ...) {
    va_list ap;
    int data;
    char str[32];
    va_start(ap, format);
    while (*format) {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 'x': case 'X':
                    data = va_arg(ap, int);
                    sprintf(str, "%x", data); myputs(str); break;
                case 'o':
                    data = va_arg(ap, int);
                    sprintf(str, "%o", data); myputs(str); break;
                case '%': putchar('%'); break;
                case 's': myputs(va_arg(ap, char*)); break;
                case 'd':
                    data = va_arg(ap, int);
                    sprintf(str, "%d", data); myputs(str); break;
                case 'c': putchar(va_arg(ap, int)); break;
                default: putchar(*format); break; // 未知格式原樣輸出
            }
        } else {
            putchar(*format);
        }
        format++;
    }
    va_end(ap);
    return 0;
}

int main() {
    myprintf("[%c]hello[%d][%s]world\n", 'A', 123, "Jason");
    myprintf("Hex: %x, Oct: %o, Percent: %%\n", 255, 255);
    return 0;
}

輸出結果

[A]hello[123][Jason]world
Hex: ff, Oct: 377, Percent: %

理解 va_list 機制,手寫 printf 其實不難,關鍵在格式解析與參數取用同步。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved