格式化字串
格式化字串(英語:format string)是一些程式語言的輸入/輸出庫中能將字串參數轉換為另一種形式輸出的函數。例如C、C++等程式語言的printf類函數,其中的轉換說明(conversion specification)用於把隨後對應的0個或多個函數參數轉換為相應的格式輸出;格式化字串中轉換說明以外的其它字元原樣輸出。[1]
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
, and0X
表示數制。0
如果width選項字首以 0
,則在左側用0
填充直至達到寬度要求。例如printf("%2d", 3)
輸出"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.ddde
[+
/-
]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
'使用大寫字母。[2][3] (C++11流使用hexfloat
輸出16進制浮點數)n
不輸出字元,但是把已經成功輸出的字元個數寫入對應的整型指標參數所指的變數。 %
' %
'字面值,不接受任何flags, width, precision or length。
寬度與精度格式化參數可以忽略,或者直接指定,或者用星號"*
"表示取對應函數參數的值。例如printf("%*d", 5, 10)
輸出" 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
函數) - 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 (頁面存檔備份,存於互聯網檔案館)
- 單一UNIX®規範第7期,由國際開放標準組織發佈 : print formatted output – 系統介面(System Interfaces)參考,
- The
Formatter
specification (頁面存檔備份,存於互聯網檔案館) in Java 1.5 - GNU Bash
printf(1)
builtin (頁面存檔備份,存於互聯網檔案館)