首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言從零手寫 printf 核心格式化輸出:%d %c %p %s 實現原理

     編輯:關於C

printf 是 C 標準庫最複雜的函數之一,但其核心格式化邏輯可通過遞歸分解與位運算在百行代碼內實現。本文實現支持 %d(十進制)、%x/%p(十六進制)、%c(字符)、%s(字符串)的精簡版 my_printf,揭示格式化輸出的底層邏輯。

核心輸出原語:putchar

所有高級輸出最終歸歸於單字符輸出 putchar(或 write(1, &ch, 1))。

十進制整數輸出:遞歸分解法

static void print_dec(unsigned int n) {
    if (n >= 10) {
        print_dec(n / 10);   // 遞歸處理高位
        n %= 10;
    }
    putchar('0' + n);        // 輸出當前最低位
}

遞歸深度 = 位數(32位 int 最大 10 層),棧開銷極小。

十六進制輸出:位掩碼與移位法

static void print_hex(unsigned int n) {
    putchar('0'); putchar('x');  // 0x 前綴
    for (int i = 7; i >= 0; i--) {  // 32位 = 8個十六進制位
        unsigned char nibble = (n >> (i * 4)) & 0xF;
        putchar(nibble < 10 ? '0' + nibble : 'a' + nibble - 10);
    }
}

字符與字符串輸出

static void print_char(char ch) { putchar(ch); }

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

簡易格式化解析器

void my_printf(const char* fmt, ...) {
    va_list ap;
    va_start(ap, fmt);
    
    for (const char* p = fmt; *p; p++) {
        if (*p != '%') {
            putchar(*p);
            continue;
        }
        p++; // 解析格式字符
        switch (*p) {
            case 'd': {
                int val = va_arg(ap, int);
                if (val < 0) { putchar('-'); print_dec(-val); }
                else print_dec(val);
                break;
            }
            case 'x':
            case 'p': {
                unsigned int val = va_arg(ap, unsigned int);
                print_hex(val);
                break;
            }
            case 'c': {
                char ch = (char)va_arg(ap, int); // char 提升為 int
                print_char(ch);
                break;
            }
            case 's': {
                const char* s = va_arg(ap, const char*);
                print_str(s);
                break;
            }
            case '%':
                putchar('%');
                break;
            default:
                putchar('%'); putchar(*p);
        }
    }
    va_end(ap);
}

測試驗證

int main() {
    my_printf("dec: %d\n", 12345);
    my_printf("hex: %x\n", 0xABCD);
    my_printf("ptr: %p\n", (void*)0x7FFFABCD);
    my_printf("char: %c\n", 'Z');
    my_printf("str: %s\n", "Hello, World!");
    my_printf("mix: %d %s %x\n", 42, "test", 0xFF);
    return 0;
}

輸出

dec: 12345
hex: 0xabcd
ptr: 0x7fffabcd
char: Z
str: Hello, World!
mix: 42 test ff

擴展方向(生產級 printf 需支持)

手寫 printf 核心邏輯是理解可變參、格式解析、數制轉換、字符輸出的綜合實戰。建議讀者在掌握本文精簡版基礎上,嘗試添加寬度/精度/標志支持,逐步逼近標準庫實現複雜度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性實現要點
寬度/精度 %10d %.2f解析 * 或數字,填充空格或 0
標志 %-+ #0左對齊、強制符號、替代形式、零填充
長度修飾 hh/h/l/ll/j/z/t對應 char/short/long/long long/intmax_t/size_t/ptrdiff_t
浮點數 %f/%e/%g/%a需實現浮點轉字符串算法(Dragon4/Grisu3)
自定義類型 %n %m%n 寫入已輸出字符數,%m 輸出 errno 字符串