格式化字符串

<image>

格式化字符串（format string）是一些程序設計語言的輸入/輸出庫中能將字串參數轉換為另一種形式輸出的函數。例如C、C++等程序設計語言的printf類函數，其中的轉換說明（conversion specification）用於把隨後對應的0個或多個函數參數轉換為相應的格式輸出；格式化字符串中轉換說明以外的其它字符原樣輸出。

## C語言printf函數為代表的一類

### 格式化占位符

格式化字符串中的占位符用於指明輸出的參數值如何格式化。

格式化占位符（format placeholder），語法是：

`%[''parameter''][''flags''][''field width''][.''precision''][''length'']''type''`

Parameter可以忽略或者是：

字符｜描述

`''n''$`｜n是用這個格式說明符（specifier）顯示第幾個參數；這使得參數可以輸出多次，使用多個格式說明符，以不同的順序輸出。如果任意一個占位符使用了parameter，則其他所有占位符必須也使用parameter。這是POSIX擴展，不屬於ISO C。例：`printf("%2$d %2$#x; %1$d %1$#x",16,17)` 產生"`17 0x11; 16 0x10`"

Flags可為0個或多個：

字符｜描述

`+`｜總是表示有符號數值的'`+`'或'`-`'號，預設情況是忽略正數的符號。僅適用於數值類型。

空格｜使得有符號數的輸出如果沒有正負號或者輸出0個字符，則前綴1個空格。如果空格與'+'同時出現，則空格說明符被忽略。

`-`｜左對齊。預設情況是右對齊。

`#`｜對於'`g`'與'`G`'，不刪除尾部0以表示精度。對於'`f`', '`F`', '`e`', '`E`', '`g`', '`G`', 總是輸出小數點。對於'`o`', '`x`', '`X`', 在非0數值前分別輸出前綴`0`, `0x`, and `0X`表示數制。

`0`｜如果width選項前綴以`0`，則在左側用`0`填充直至達到寬度要求。例如`printf("%2d", 3)`輸出"`&nbsp;3`"，而`printf("%02d", 3)`輸出"`03`"。如果`0`與`-`均出現，則`0`被忽略，即左對齊依然用空格填充。

Field Width給出顯示數值的最小寬度，典型用於制表輸出時填充固定寬度的表目。實際輸出字符的個數不足域寬，則根據左對齊或右對齊進行填充。實際輸出字符的個數超過域寬並不引起數值截斷，而是顯示全部。寬度值的前導0被解釋為0填充標誌，如上述；前導的負值被解釋為其絕對值，負號解釋為左對齊標誌。如果域寬值為`*`，則由對應的函數參數的值為當前域寬。

Precision通常指明輸出的最大長度，依賴於特定的格式化類型。對於d、i、u、x、o的整型數值，是指最小數字位數，不足的位要在左側補0，如果超過也不截斷，預設值為1。對於a,A,e,E,f,F的浮點數值，是指小數點右邊顯示的數字位數，必要時四捨五入或補0；預設值為6。對於g,G的浮點數值，是指有效數字的最大位數；預設值為6。對於s的字串類型，是指輸出的字節的上限，超出限制的其它字符將被截斷。如果域寬為`*`，則由對應的函數參數的值為當前域寬。如果僅給出了小數點，則域寬為0。

Length指出浮點型參數或整型參數的長度。此項Microsoft稱為「Size」。可以忽略，或者是下述：

字符｜描述

`hh`｜對於整數類型，`printf`期待一個從`char`提升的`int`尺寸的整型參數。

`h`｜對於整數類型，`printf`期待一個從`short`提升的`int`尺寸的整型參數。

`l`｜對於整數類型，`printf`期待一個`long`尺寸的整型參數。對於浮點類型，`printf`期待一個`double`尺寸的整型參數。對於字串s類型，`printf`期待一個`wchar_t`指針參數。對於字符c類型，`printf`期待一個`wint_t`型的參數。

`ll`｜對於整數類型，`printf`期待一個`long long`尺寸的整型參數。Microsoft也可以使用`I64`。

`L`｜對於浮點類型，`printf`期待一個`long double`尺寸的整型參數。

`z`｜對於整數類型，`printf`期待一個`size_t`尺寸的整型參數。

`j`｜對於整數類型，`printf`期待一個`intmax_t`尺寸的整型參數。

`t`｜對於整數類型，`printf`期待一個`ptrdiff_t`尺寸的整型參數。

此外，在ISO C99廣泛接受前，還有幾個平台相關的length選項：

字符｜描述

`I`｜對於有符號整數類型，`printf`期待一個`ptrdiff_t`尺寸的整型參數。對於無符號整數類型，`printf`期待一個`size_t`尺寸的整型參數。常見於Win32/Win64平台。

`I32`｜對於整數類型，`printf`期待一個32位（雙字）的整型參數。常見於Win32/Win64平台。

`I64`｜對於整數類型，`printf`期待一個64位（四字）的整型參數。常見於Win32/Win64平台。

`q`｜對於整數類型，`printf`期待一個64位（四字）的整型參數。常見於BSD平台。

ISO C99的頭文件`inttypes.h`包含了許多宏，用於平台獨立的`printf`編碼。例如：

宏｜定義

`PRId32`｜典型地等效於`I32d` (Win32/Win64)或`d`

`PRId64`｜典型地等效於`I64d` (Win32/Win64), `lld` (32位平台)或`ld` (64位平台)

`PRIi32`｜典型地等效於`I32i` (Win32/Win64)或`i`

`PRIi64`｜典型地等效於`I64i` (Win32/Win64), `lli` (32位平台)或`li` (64位平台)

`PRIu32`｜典型地等效於`I32u` (Win32/Win64)或`u`

`PRIu64`｜典型地等效於`I64u` (Win32/Win64), `llu` (32位平台)或`lu` (64位平台)

`PRIx32`｜典型地等效於`I32x` (Win32/Win64)或`x`

`PRIx64`｜典型地等效於`I64x` (Win32/Win64), `llx` (32位平台)或`lx` (64位平台)

### 類型

Type，也稱轉換說明（conversion specification/specifier），可以是：

字符｜描述

`d`, `i`｜有符號十進位數值`int`。'`%d`'與'`%i`'對於輸出是同義；但對於`scanf()`輸入二者不同，其中`%i`在輸入值有前綴`0x`或0時，分別表示16進位或8進位的值。如果指定了精度，則輸出的數字不足時在左側補0。默認精度為1。精度為0且值為0，則輸出為空。

`u`｜十進位`unsigned int`。如果指定了精度，則輸出的數字不足時在左側補0。默認精度為1。精度為0且值為0，則輸出為空。

`f`, `F`｜`double`型輸出10進位定點表示。'`f`'與'`F`'差異是表示無窮與NaN時，'`f`'輸出'`inf`', '`infinity`'與'`nan`'；'`F`'輸出'`INF`', '`INFINITY`'與'`NAN`'。小數點後的數字位數等於精度，最後一位數字四捨五入。精度默認為6。如果精度為0且沒有#標記，則不出現小數點。小數點左側至少一位數字。

`e`, `E`｜`double`值，輸出形式為10進位的(`-`d.ddd `e``+`/`-`ddd). `E`版本使用的指數符號為`E`（而不是`e`）。指數部分至少包含2位數字，如果值為0，則指數部分為`00`。Windows系統，指數部分至少為3位數字，例如`1.5e002`，也可用Microsoft版的運行時函數`_set_output_format` 修改。小數點前存在1位數字。小數點後的數字位數等於精度。精度默認為6。如果精度為0且沒有#標記，則不出現小數點。

`g`, `G`｜`double`型數值，精度定義為全部有效數字位數。當指數部分在閉區間 -4,5 內，輸出為定點形式；否則輸出為指數浮點形式。'`g`'使用小寫字母，'`G`'使用大寫字母。小數點右側的尾數0不被顯示；顯示小數點僅當輸出的小數部分不為0。

`x`, `X`｜16進位`unsigned int`。'`x`'使用小寫字母；'`X`'使用大寫字母。如果指定了精度，則輸出的數字不足時在左側補0。默認精度為1。精度為0且值為0，則輸出為空。

`o`｜8進位`unsigned int`。如果指定了精度，則輸出的數字不足時在左側補0。默認精度為1。精度為0且值為0，則輸出為空。

`s`｜如果沒有用l標誌，輸出null結尾字串直到精度規定的上限；如果沒有指定精度，則輸出所有字節。如果用了l標誌，則對應函數參數指向wchar_t型的陣列，輸出時把每個寬字符轉化為多字節字符，相當於調用`wcrtomb`函數。

`c`｜如果沒有用l標誌，把int參數轉為`unsigned char`型輸出；如果用了l標誌，把wint_t參數轉為包含兩個元素的`wchart_t`陣列，其中第一個元素包含要輸出的字符，第二個元素為null寬字符。

`p`｜`void *`型

`a`, `A`｜`double`型的16進位表示，"−0xh.hhhh p±d"。其中指數部分為10進位表示的形式。例如：1025.010輸出為0x1.004000p+10。'`a`'使用小寫字母，'`A`'使用大寫字母。（C++11流使用`hexfloat`輸出16進位浮點數）

`n`｜不輸出字符，但是把已經成功輸出的字符個數寫入對應的整型指針參數所指的變量。

`%`｜'`%`'字面值，不接受任何flags, width, precision or length。

寬度與精度格式化參數可以忽略，或者直接指定，或者用星號"`*`"表示取對應函數參數的值。例如`printf("%*d", 5, 10)`輸出"`&nbsp;&nbsp;&nbsp;10`"；`printf("%.*s", 3, "abcdef")` 輸出"`abc`"。

如果函數參數太少，不能匹配所有的格式參數說明符，或者函數參數的類型不匹配，將導致未定義（undefined）行為。過多的函數參數被忽略。許多時候，未定義的行為將導致格式化字符串攻擊。

某些編譯器，如GCC，會靜態檢查printf這一類函數的格式化參數並編譯警告存在的問題（當使用編譯標誌`-Wall`或`-Wformat`）。GCC也會對使用者自定義的printf風格函數做靜態檢查，如果在函數定義時使用了非標準的 `__attribute__((format(...)))`。

### 具有printf風格函數的程式語言

- AMPL
- awk (通過sprintf)
- Bourne shell (sh)以及變種Korn shell (ksh), Bourne again shell (bash), Z shell (zsh)
- C
- C++ (以及iostream與iomanip輸出操作)
- Objective-C
- Clojure
- Common Lisp
- D
- F#
- GNU MathProg
- GNU Octave
- G (LabVIEW)
- Go
- Haskell
- Java （版本1.5開始，在`PrintStream`類提供了`printf`函數）
- Clojure
- Scala
- Lua (string.format)
- Maple
- Mathematica
- MATLAB
- Mythryl
- OCaml
- (OCaml Batteries Included provides an additional user-extensible printf)
- PARI/GP
- PHP
- Perl
- Python (使用%操作符。2.6版以後提供了format方法。)
- R
- Ruby
- Rust
- Tcl (通過format命令)
- Transact-SQL (通過 xp_sprintf )
- Vala (通過`print()`與`FileStream.printf()`)

此外，Windows API的FormatMessage函數也使用格式化字符串說明。

## 外部連結

- C++ reference for `std::fprintf`
- gcc printf format specifications quick reference
- The `Formatter` specification in Java 1.5
- GNU Bash `printf(1)` builtin