天天看點

printf()詳解之終極無惑1.printf()簡介2.格式控制字元串詳解3.轉義字元4.關于printf緩沖5.小結

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",&amp;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

輸出結果為: 

printf()詳解之終極無惑1.printf()簡介2.格式控制字元串詳解3.轉義字元4.關于printf緩沖5.小結

用十進制整數來表示輸出的最少位數。若實際位數多于指定的寬度,則按實際位數輸出,若實際位數少于定義的寬度則補以空格或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)應運而生,成為格式控制字元串的一部分。

printf()詳解之終極無惑1.printf()簡介2.格式控制字元串詳解3.轉義字元4.關于printf緩沖5.小結

注意:黃色背景行辨別的類型長度說明符和相應的資料類型是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,如需轉載請自行聯系原作者