為什麼 printf("%%s") 能輸出 %s,而 printf("\045") 不能輸出 %?這觸及 printf 格式字串解析的核心機制。本文從編譯器預處理、運行時解析兩個階段徹底講透。
printf("%%s"); // 輸出: %s ✓
printf("\045s"); // 輸出: %s ✓ (注意: \045 是八進制 % )
printf("\045"); // 輸出: (空) ✗ 為什麼?
printf("\044"); // 輸出: $ ✓
"%%s" → 字串常值內容為 %s(兩個字元)"\045s" → 字串常值內容為 %s(\045 八進制 = 37 十進制 = ASCII %)"\045" → 字串常值內容為 %(單一字元)"\044" → 字串常值內容為 $(單一字元)關鍵:編譯器只負責把轉義序列翻譯成對應 ASCII 字元,不關心 printf 格式語法。
printf 掃描格式字串,遇到 % 視為格式佔位符開始,期待後續跟隨型別字元(d、s、f...)。
| 傳入字串 | printf 掃描過程 | 結果 |
|---|---|---|
%s | 見 % → 期待型別 → 見 s → 字串格式 → 尋找對應參數 → 無參數 → 未定義行為 | 崩潰/亂碼 |
%%s | 見 %% → 特殊規則:輸出單個 % → 見 s → 普通字元 → 輸出 s | %s |
% (單獨) | 見 % → 期待型別 → 字串結束 → 格式不完整 → 未定義行為 | 無輸出/崩潰 |
$ | 非 % → 普通字元直接輸出 | $ |
printf("\045") 無輸出?\045 被編譯器解析為單一字元 %。printf 收到 "%",視為未完整的格式佔位符,觸發未定義行為(通常無輸出或崩潰)。
printf("\045\045") 能輸出 %?編譯器解析為 "%%",printf 見 %% 按特殊規則輸出單個 %。
$ 不需要轉義?$ 在 printf 格式字串中無特殊含義,是普通字元,直接輸出。只有 % 是格式佔位符前導符。
%%,輸出單個 %(printf 專屬規則)\045,編譯器變 %,printf 以為是格式符 → 危險%,老實寫 %%scanf("%%d", &x) 會嘗試匹配輸入中的字面 %d 字串,而非讀取整數。
%% 是 printf/scanf 運行時的格式轉義規則;\045 是編譯器的字元常量八進制轉義。兩者作用階段不同,混用必出 Bug。輸出百分號,請永遠使用 %%。