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

C 語言核心 printf 來源碼逐行解析:變長參數、格式解析與底層輸出

     編輯:關於C語言

函數簽名與變長參數初始化

int printf(const char *cntrl_string, ...) {
    int pos = 0, cnt_printed_chars = 0, i;
    unsigned char *chptr;
    va_list ap;
    va_start(ap, cntrl_string); // 初始化變長參數列表
    // ...
}

主迴圈:掃描格式字串

while (cntrl_string[pos]) {
    if (cntrl_string[pos] == '%') {
        ++pos;
        switch (cntrl_string[pos]) {
            case 'c': putchar(va_arg(ap, unsigned char)); ++cnt_printed_chars; break;
            case 's': chptr = va_arg(ap, unsigned char*);
                      while (chptr[i]) { putchar(chptr[i++]); ++cnt_printed_chars; } break;
            case 'i': case 'd': cnt_printed_chars += printInt(va_arg(ap, int)); break;
            case 'u': cnt_printed_chars += printUnsignedInt(va_arg(ap, unsigned int)); break;
            case 'x': cnt_printed_chars += printHexa(va_arg(ap, unsigned int), 'x'); break;
            case 'X': cnt_printed_chars += printHexa(va_arg(ap, unsigned int), 'X'); break;
            case 'o': cnt_printed_chars += printOctal(va_arg(ap, unsigned int)); break;
            case 'p': putchar('0'); putchar('x'); cnt_printed_chars+=2;
                      cnt_printed_chars += printHexa(va_arg(ap, unsigned int), 'x'); break;
            case '#': ++pos; // 處理 #x, #X, #o 等替代格式
                      switch (cntrl_string[pos]) { /* 類似上述,加前綴 */ } break;
            default: putchar(cntrl_string[pos]); ++cnt_printed_chars; // 未知格式直接輸出
        }
    } else {
        putchar(cntrl_string[pos]); ++cnt_printed_chars; // 普通字元直接輸出
    }
    ++pos;
}
va_end(ap);
return cnt_printed_chars;

底層字元輸出 putchar 與 printChar

int putchar(int c) {
    switch ((unsigned char)c) {
        case '\n': newLine(); break;
        case '\r': carriageReturn(); break;
        case '\f': clearScreen(); break;
        case '\t': for(int i=0;i<8;++i) printChar(32); break; // 8 spaces
        case '\b': backspace(); break;
        case '\a': beep(); break;
        default: printChar(c);
    }
    return c;
}

void printChar(const byte ch) {
    *(word*)(VIDEO + y*160 + x*2) = ch | (fill_color << 8); // 直接寫顯存 0xB8000
    ++x;
    if (x >= WIDTH) newLine();
    setVideoCursor(y, x);
}

VIDEO = 0xB8000 為文字模式顯存基址,每字元佔 2 位元組 (ASCII + 屬性/顏色)。

關鍵設計觀察

  1. 變長參數處理:標準 va_start/arg/end 機制,型別安全由程式設計師依格式字串保證。
  2. 格式解析:單趟掃描,switch 分派,支援基本型別與 # 替代格式。
  3. 缺乏寬度/精度/旗標支援:教學級實作,標準庫 printf 需解析 %[flags][width][.precision][length]specifier。
  4. 直接操作硬體:適合作業系統核心/裸機環境,用戶態程式應呼叫 C 執行期庫 printf (經由系統呼叫輸出)。
  5. 回傳列印字元數:符合 C99 標準 printf 回傳值語意。

擴充方向

  • 支援 %ld, %lld, %f, %p 等長度修飾與指標格式。
  • 實作 vsnprintf 以支援緩衝區輸出與長度限制。
  • 引入快取緩衝區減少顯存寫入次數。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved