printf()是C語言标準庫函數,用于将格式化後的字元串輸出到标準輸出。标準輸出,即标準輸出檔案,對應終端的螢幕。printf()申明于頭檔案stdio.h。
函數原型:
1
傳回值:
正确傳回輸出的字元總數,錯誤傳回負值,與此同時,輸入輸出流錯誤标志将被置值,可由訓示器ferror來檢查輸入輸出流的錯誤标志。
調用格式:
printf()函數的調用格式為:<code>printf("格式化字元串",輸出表列)</code>。
格式化字元串包含三種對象,分别為:
(1)字元串常量;
(2)格式控制字元串;
(3)轉義字元。
字元串常量原樣輸出,在顯示中起提示作用。輸出表列中給出了各個輸出項,要求格式控制字元串和各輸出項在數量和類型上應該一一對應。其中格式控制字元串是以%開頭的字元串,在%後面跟有各種格式控制符,以說明輸出資料的類型、寬度、精度等。
注:本文的所有示例代碼均在Linux環境下以g++ 4.4.6編譯成64位程式的執行。
printf的格式控制字元串組成如下:
分别為:
首先說明類型,因為類型是格式控制字元串的重中之重,是必不可少的組成部分,其它的選項都是可選的。type用于規定輸出資料的類型,含義如下:
字元
對應資料類型
含義
示例
d/i
int
輸出十進制有符号32bits整數,i是老式寫法
<code>printf("%i",123);</code>輸出123
o
unsigned int
無符号8進制(octal)整數(不輸出字首0)
<code>printf("0%o",123);</code>輸出0173
u
無符号10進制整數
<code>printf("%u",123);</code>輸出123
x/X
無符号16進制整數,x對應的是abcdef,X對應的是ABCDEF(不輸出字首0x)
<code>printf("0x%x 0x%X",123,123);</code>輸出0x7b 0x7B
f/lf
float(double)
單精度浮點數用f,雙精度浮點數用lf(printf可混用,但scanf不能混用)
<code>printf("%.9f %.9lf",0.000000123,0.000000123);</code>輸出0.000000123 0.000000123。注意指定精度,否則printf預設精确到小數點後六位
e/E
科學計數法,使用指數(Exponent)表示浮點數,此處”e”的大小寫代表在輸出時“e”的大小寫
<code>printf("%e %E",0.000000123,0.000000123);</code>輸出1.230000e-07 1.230000E-07
g
根據數值的長度,選擇以最短的方式輸出,%f或%e
<code>printf("%g %g",0.000000123,0.123);</code>輸出1.23e-07 0.123
G
根據數值的長度,選擇以最短的方式輸出,%f或%E
<code>printf("%G %G",0.000000123,0.123);</code>輸出1.23E-07 0.123
c
char
字元型。可以把輸入的數字按照ASCII碼相應轉換為對應的字元
<code>printf("%c\n",64)</code>輸出A
s
char*
字元串。輸出字元串中的字元直至字元串中的空字元(字元串以空字元’\0‘結尾)
<code>printf("%s","測試test");</code>輸出:測試test
S
wchar_t*
寬字元串。輸出字元串中的字元直至字元串中的空字元(寬字元串以兩個空字元’\0‘結尾)
<code>setlocale(LC_ALL,"zh_CN.UTF-8");</code>
<code>wchar_t wtest[]=L"測試Test";</code>
<code>printf("%S\n",wtest);</code>
輸出:測試test
p
void*
以16進制形式輸出指針
<code>printf("%010p","lvlv");</code>輸出:0x004007e6
n
int*
什麼也不輸出。%n對應的參數是一個指向signed int的指針,在此之前輸出的字元數将存儲到指針所指的位置
<code>int num=0;</code>
<code>printf("lvlv%n",&num);</code>
<code>printf("num:%d",num);</code>
輸出:lvlvnum:4
%
字元%
輸出字元‘%’(百分号)本身
<code>printf("%%");</code>輸出:%
m
無
列印errno值對應的出錯内容
<code>printf("%m\n");</code>
a/A
十六進制p計數法輸出浮點數,a為小寫,A為大寫
<code>printf("%a %A",15.15,15.15);</code>輸出:0x1.e4ccccccccccdp+3 0X1.E4CCCCCCCCCCDP+3
注意:
(1)使用printf輸出寬字元時,需要使用setlocale指定本地化資訊并同時指明目前代碼的編碼方式。除了使用%S,還可以使用%ls。
(2)%a和%A是C99引入的格式化類型,采用十六進制p計數法輸出浮點數。p計數法類似E科學計數法,但不同。數以0x開頭,然後是16進制浮點數部分,接着是p後面是以 2為底的階碼。以上面輸出的15.15為例,推算輸出結果。15.15轉換成二進制為<code>1111.00 1001 1001 1001 1001 ...</code>,因為二進制表示數值的離散特點,計算機對于小數有時是不能精确表示的,比如0.5可以精确表示為0.12,而0.15卻不能精确表示。将15.15對應的二進制右移三位,為<code>1.1110 0100 1100 1100 1100 ...</code>轉換對應的十六進制就是0x1.e4ccccccccccd,注意舍入時向高位進了1位。由于右移三位,是以二進制階碼就是3。最後的結果就是0x1.e4ccccccccccdp+3。
(3)格式控制字元串除了指明輸出的資料類型,還可以包含一些其它的可選的格式說明,依序有 flags, width, .precision and length。下面一一講解。
flags規定輸出樣式,取值和含義如下:
名稱
說明
-
減号
結果左對齊,右邊填空格。預設是右對齊,左邊填空格。
+
加号
輸出符号(正号或負号)
space
空格
輸出值為正時加上空格,為負時加上負号
#
井号
type是o、x、X時,增加字首0、0x、0X。
type是a、A、e、E、f、g、G時,一定使用小數點。預設的,如果沒有小數部分則不輸出小數點。
type是g、G時,尾部的0保留。
數字零
将輸出的前面補上0,直到占滿指定列寬為止(不可以搭配使用“-”)
示例:
2
3
4
5
6
7
8
9
10
11
12
13
14
輸出結果為:
用十進制整數來表示輸出的最少位數。若實際位數多于指定的寬度,則按實際位數輸出,若實際位數少于定義的寬度則補以空格或0。width的可能取值如下:
width
描述
數值
十進制整數
<code>printf("%06d",1000);</code>輸出:001000
*
星号。不顯示指明輸出最小寬度,而是以星号代替,在printf的輸出參數清單中給出
<code>printf("%0*d",6,1000);</code>輸出:001000
精度格式符以“.”開頭,後跟十進制整數。可取值如下:
.precision
.數值
十進制整數。
(1)對于整型(d,i,o,u,x,X),precision表示輸出的最小的數字個數,不足補前導零,超過不截斷。
(2)對于浮點型(a, A, e, E, f ),precision表示小數點後數值位數,預設為六位,不足補後置0,超過則截斷。
(3)對于類型說明符g或G,表示可輸出的最大有效數字。
(4)對于字元串(s),precision表示最大可輸出字元數,不足正常輸出,超過則截斷。
precision不顯示指定,則預設為0
.*
以星号代替數值,類似于width中的*,在輸出參數清單中指定精度。
輸出結果:
注意,在對浮點數和整數截斷時,存在四舍五入。
類型長度指明待輸出資料的長度。因為相同類型可以有不同的長度,比如整型有16bits的short int,32bits的int,也有64bits的long int,浮點型有32bits的單精度float和64bits的雙精度double。為了指明同一類型的不同長度,于是乎,類型長度(length)應運而生,成為格式控制字元串的一部分。
注意:黃色背景行辨別的類型長度說明符和相應的資料類型是C99引入的。
示例代碼:
long int到底是32bits還是64bits跟生成的程式是32bits還是64bits一一對應,如果使用g++編譯程式的話,可通過<code>-m32</code>或<code>-m64</code>選項分别生成32bits和64bits的程式。因本人測試代碼編譯生成的是64bits的程式,是以long int也就是64btis。
轉義字元在字元串中會被自動轉換為相應操作指令。printf()使用的常見轉義字元如下:
轉義字元
意義
\a
警報(響鈴)符
\b
回退符
\f
換頁符
\n
換行符
\r
回車符
\t
橫向制表符
\v
縱向制表符
\\
反斜杠
\”
雙引号
在printf的實作中,在調用write之前先寫入IO緩沖區,這是一個使用者空間的緩沖。系統調用是軟中斷,頻繁調用,需要頻繁陷入核心态,這樣的效率不是很高,而printf實際是向使用者空間的IO緩沖寫,在滿足條件的情況下才會調用write系統調用,減少IO次數,提高效率。
printf在glibc中預設為行緩沖,遇到一下幾種情況會重新整理緩沖區,輸出内容:
(1)緩沖區填滿;
(2)寫入的字元中有換行符<code>\n</code>或回車符<code>\r</code>;
(3)調用fflush手動重新整理緩沖區;
(4)調用scanf要從輸入緩沖區中讀取資料時,也會将輸出緩沖區内的資料重新整理。
可使用<code>setbuf(stdout,NULL)</code>關閉行緩沖,或者<code>setbuf(stdout,uBuff)</code>設定新的緩沖區,uBuff為自己指定的緩沖區。也可以使用<code>setvbuf(stdout,NULL,_IOFBF,0);</code>來改變标準輸出為全緩沖。全緩沖與行緩沖的差別在于遇到換行符不重新整理緩沖區。
printf在VC++中預設關閉緩沖區,且隻能設定全緩沖。輸出時會及時的輸到螢幕[3]。因為微軟閉源,是以無法研究printf函數的實作源碼。
耗時将近兩天,終于完成了此篇看似基礎,但卻紛繁複雜的printf()用法。由于時間和個人水準有限,文章不足之處在所難免,也請讀者批評指正,不甚感激。
printf和wprintf不能同時輸出寬字元串的示例代碼如下:
上面的代碼中語句1和語句二不能同時存在,否則隻能正常輸出第一個。原因尚不清楚,估計和wprintf和printf内部實作有關,也不知道在Windows平台是否也存在這種問題,有興趣的讀者可以嘗試一下。下一篇博文預估将集結全部火力,探讨解決這個問題,wprintf的具體用法,字元編碼等相關問題,敬請期待。
本文轉自莫水千流部落格園部落格,原文連結:http://www.cnblogs.com/zhoug2020/p/7676586.html,如需轉載請自行聯系原作者