久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

printf()詳解之終極無惑

 圓錐的布袋 2018-01-25

1.printf()簡介

printf()是C語言標(biāo)準(zhǔn)庫函數(shù),,用于將格式化后的字符串輸出到標(biāo)準(zhǔn)輸出。標(biāo)準(zhǔn)輸出,,即標(biāo)準(zhǔn)輸出文件,,對(duì)應(yīng)終端的屏幕。printf()申明于頭文件stdio.h,。

函數(shù)原型:

int printf ( const char * format, ... );
  • 1

返回值:
正確返回輸出的字符總數(shù),,錯(cuò)誤返回負(fù)值,與此同時(shí),,輸入輸出流錯(cuò)誤標(biāo)志將被置值,,可由指示器ferror來檢查輸入輸出流的錯(cuò)誤標(biāo)志。

調(diào)用格式:
printf()函數(shù)的調(diào)用格式為:printf("格式化字符串",輸出表列),。

格式化字符串包含三種對(duì)象,,分別為:
(1)字符串常量;
(2)格式控制字符串,;
(3)轉(zhuǎn)義字符,。
字符串常量原樣輸出,在顯示中起提示作用,。輸出表列中給出了各個(gè)輸出項(xiàng),,要求格式控制字符串和各輸出項(xiàng)在數(shù)量和類型上應(yīng)該一一對(duì)應(yīng)。其中格式控制字符串是以%開頭的字符串,,在%后面跟有各種格式控制符,,以說明輸出數(shù)據(jù)的類型、寬度,、精度等。

注:本文的所有示例代碼均在Linux環(huán)境下以g++ 4.4.6編譯成64位程序的執(zhí)行,。

2.格式控制字符串詳解

printf的格式控制字符串組成如下:

%[flags][width][.prec][length]type
  • 1

分別為:

%[標(biāo)志][最小寬度][.精度][類型長度]類型,。
  • 1

2.1類型(type)

首先說明類型,,因?yàn)轭愋褪歉袷娇刂谱址闹刂兄兀潜夭豢缮俚慕M成部分,,其它的選項(xiàng)都是可選的,。type用于規(guī)定輸出數(shù)據(jù)的類型,含義如下:

字符 對(duì)應(yīng)數(shù)據(jù)類型 含義 示例
d/i int 輸出十進(jìn)制有符號(hào)32bits整數(shù),,i是老式寫法 printf("%i",123);輸出123
o unsigned int 無符號(hào)8進(jìn)制(octal)整數(shù)(不輸出前綴0) printf("0%o",123);輸出0173
u unsigned int 無符號(hào)10進(jìn)制整數(shù) printf("%u",123);輸出123
x/X unsigned int 無符號(hào)16進(jìn)制整數(shù),,x對(duì)應(yīng)的是abcdef,X對(duì)應(yīng)的是ABCDEF(不輸出前綴0x) printf("0x%x 0x%X",123,123);輸出0x7b 0x7B
f/lf float(double) 單精度浮點(diǎn)數(shù)用f,雙精度浮點(diǎn)數(shù)用lf(printf可混用,,但scanf不能混用) printf("%.9f %.9lf",0.000000123,0.000000123);輸出0.000000123 0.000000123,。注意指定精度,否則printf默認(rèn)精確到小數(shù)點(diǎn)后六位
F float(double) 與f格式相同,,只不過 infinity 和 nan 輸出為大寫形式,。 例如printf("%f %F %f %F\n",INFINITY,INFINITY,NAN,NAN);輸出結(jié)果為inf INF nan NAN
e/E float(double) 科學(xué)計(jì)數(shù)法,使用指數(shù)(Exponent)表示浮點(diǎn)數(shù),,此處”e”的大小寫代表在輸出時(shí)“e”的大小寫 printf("%e %E",0.000000123,0.000000123);輸出1.230000e-07 1.230000E-07
g float(double) 根據(jù)數(shù)值的長度,,選擇以最短的方式輸出,%f或%e printf("%g %g",0.000000123,0.123);輸出1.23e-07 0.123
G float(double) 根據(jù)數(shù)值的長度,,選擇以最短的方式輸出,,%f或%E printf("%G %G",0.000000123,0.123);輸出1.23E-07 0.123
c char 字符型??梢园演斎氲臄?shù)字按照ASCII碼相應(yīng)轉(zhuǎn)換為對(duì)應(yīng)的字符 printf("%c\n",64)輸出A
s char* 字符串,。輸出字符串中的字符直至字符串中的空字符(字符串以空字符’\0‘結(jié)尾) printf("%s","測(cè)試test");輸出:測(cè)試test
S wchar_t* 寬字符串。輸出字符串中的字符直至字符串中的空字符(寬字符串以兩個(gè)空字符’\0‘結(jié)尾) setlocale(LC_ALL,"zh_CN.UTF-8");
wchar_t wtest[]=L"測(cè)試Test";
printf("%S\n",wtest);
輸出:測(cè)試test
p void* 以16進(jìn)制形式輸出指針 printf("%010p","lvlv");輸出:0x004007e6
n int* 什么也不輸出,。%n對(duì)應(yīng)的參數(shù)是一個(gè)指向signed int的指針,,在此之前輸出的字符數(shù)將存儲(chǔ)到指針?biāo)傅奈恢?/td> int num=0;
printf("lvlv%n",&num);
printf("num:%d",num);
輸出:lvlvnum:4
% 字符% 輸出字符‘%’(百分號(hào))本身 printf("%%");輸出:%
m 打印errno值對(duì)應(yīng)的出錯(cuò)內(nèi)容 printf("%m\n");
a/A float(double) 十六進(jìn)制p計(jì)數(shù)法輸出浮點(diǎn)數(shù),a為小寫,,A為大寫 printf("%a %A",15.15,15.15);輸出:0x1.e4ccccccccccdp+3 0X1.E4CCCCCCCCCCDP+3

注意:
(1)使用printf輸出寬字符時(shí),,需要使用setlocale指定本地化信息并同時(shí)指明當(dāng)前代碼的編碼方式。除了使用%S,,還可以使用%ls,。
(2)%a和%A是C99引入的格式化類型,采用十六進(jìn)制p計(jì)數(shù)法輸出浮點(diǎn)數(shù),。p計(jì)數(shù)法類似E科學(xué)計(jì)數(shù)法,,但不同。數(shù)以0x開頭,,然后是16進(jìn)制浮點(diǎn)數(shù)部分,,接著是p后面是以 2為底的階碼。以上面輸出的15.15為例,,推算輸出結(jié)果,。15.15轉(zhuǎn)換成二進(jìn)制為1111.00 1001 1001 1001 1001 ...,,因?yàn)槎M(jìn)制表示數(shù)值的離散特點(diǎn),計(jì)算機(jī)對(duì)于小數(shù)有時(shí)是不能精確表示的,,比如0.5可以精確表示為0.12,,而0.15卻不能精確表示。將15.15對(duì)應(yīng)的二進(jìn)制右移三位,,為1.1110 0100 1100 1100 1100 ...轉(zhuǎn)換對(duì)應(yīng)的十六進(jìn)制就是0x1.e4ccccccccccd,,注意舍入時(shí)向高位進(jìn)了1位。由于右移三位,,所以二進(jìn)制階碼就是3,。最后的結(jié)果就是0x1.e4ccccccccccdp+3。

(3)格式控制字符串除了指明輸出的數(shù)據(jù)類型,,還可以包含一些其它的可選的格式說明,,依序有 flags, width, .precision and length。下面一一講解,。

2.2標(biāo)志(flags)

flags規(guī)定輸出樣式,,取值和含義如下:

字符 名稱 說明
- 減號(hào) 結(jié)果左對(duì)齊,右邊填空格,。默認(rèn)是右對(duì)齊,,左邊填空格。
+ 加號(hào) 輸出符號(hào)(正號(hào)或負(fù)號(hào))
space 空格 輸出值為正時(shí)加上空格,,為負(fù)時(shí)加上負(fù)號(hào)
# 井號(hào) type是o,、x、X時(shí),,增加前綴0,、0x、0X,。
type是a,、A、e,、E,、f、g,、G時(shí),,一定使用小數(shù)點(diǎn)。默認(rèn)的,,如果沒有小數(shù)部分則不輸出小數(shù)點(diǎn),。
type是g、G時(shí),尾部的0保留,。
0 數(shù)字零 將輸出的前面補(bǔ)上0,,直到占滿指定列寬為止(不可以搭配使用“-”)


示例:

printf("%5d\n",1000);           //默認(rèn)右對(duì)齊,左邊補(bǔ)空格
printf("%-5d\n",1000);          //左對(duì)齊,右邊補(bǔ)空格

printf("%+d %+d\n",1000,-1000); //輸出正負(fù)號(hào)

printf("% d % d\n",1000,-1000); //正號(hào)用空格替代,,負(fù)號(hào)輸出

printf("%x %#x\n",1000,1000);   //輸出0x

printf("%.0f %#.0f\n",1000.0,1000.0)//當(dāng)小數(shù)點(diǎn)后沒有值時(shí)依然輸出小數(shù)點(diǎn)

printf("%g %#g\n",1000.0,1000.0);   //保留小數(shù)點(diǎn)后后的0

printf("%05d\n",1000);  //前面補(bǔ)0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

輸出結(jié)果為:
這里寫圖片描述

2.3輸出最小寬度(width)

用十進(jìn)制整數(shù)來表示輸出的最少位數(shù),。若實(shí)際位數(shù)多于指定的寬度,則按實(shí)際位數(shù)輸出,,若實(shí)際位數(shù)少于定義的寬度則補(bǔ)以空格或0,。width的可能取值如下:

width 描述 示例
數(shù)值 十進(jìn)制整數(shù) printf("%06d",1000);輸出:001000
* 星號(hào)。不顯示指明輸出最小寬度,,而是以星號(hào)代替,,在printf的輸出參數(shù)列表中給出 printf("%0*d",6,1000);輸出:001000

2.4精度(.precision)

精度格式符以“.”開頭,后跟十進(jìn)制整數(shù),??扇≈等缦拢?/p>

.precision描述
.數(shù)值 十進(jìn)制整數(shù)。
(1)對(duì)于整型(d,i,o,u,x,X),precision表示輸出的最小的數(shù)字個(gè)數(shù),,不足補(bǔ)前導(dǎo)零,,超過不截?cái)唷?br data-filtered="filtered">(2)對(duì)于浮點(diǎn)型(a, A, e, E, f ),precision表示小數(shù)點(diǎn)后數(shù)值位數(shù),,默認(rèn)為六位,,不足補(bǔ)后置0,超過則截?cái)唷?br data-filtered="filtered">(3)對(duì)于類型說明符g或G,,表示可輸出的最大有效數(shù)字,。
(4)對(duì)于字符串(s),precision表示最大可輸出字符數(shù),,不足正常輸出,,超過則截?cái)唷?br data-filtered="filtered">precision不顯示指定,則默認(rèn)為0
.* 以星號(hào)代替數(shù)值,,類似于width中的*,,在輸出參數(shù)列表中指定精度。


示例:

printf("%.8d\n",1000);  //不足指定寬度補(bǔ)前導(dǎo)0,,效果等同于%06d
printf("%.8f\n",1000.123456789);    //超過精度,,截?cái)?printf("%.8f\n",1000.123456);   //不足精度,補(bǔ)后置0
printf("%.8g\n",1000.123456);   //最大有效數(shù)字為8位
printf("%.8s\n",“abcdefghij”);  //超過指定長度截?cái)?/code>
  • 1
  • 2
  • 3
  • 4
  • 5

輸出結(jié)果:

00001000
1000.12345679
1000.12345600
1000.1235
abcdefgh
  • 1
  • 2
  • 3
  • 4
  • 5

注意,,在對(duì)浮點(diǎn)數(shù)和整數(shù)截?cái)鄷r(shí),,存在四舍五入。

2.5類型長度(length)

類型長度指明待輸出數(shù)據(jù)的長度,。因?yàn)橄嗤愋涂梢杂胁煌拈L度,,比如整型有16bits的short int,32bits的int,,也有64bits的long int,,浮點(diǎn)型有32bits的單精度float和64bits的雙精度double,。為了指明同一類型的不同長度,于是乎,,類型長度(length)應(yīng)運(yùn)而生,,成為格式控制字符串的一部分。

因?yàn)镸arkdown表格不支持單元格合并,,背景顏色等樣式,,所以直接引用printf.C++ reference的表格。
這里寫圖片描述

注意:黃色背景行標(biāo)識(shí)的類型長度說明符和相應(yīng)的數(shù)據(jù)類型是C99引入的,。

示例代碼:

printf("%hhd\n",'A');       //輸出有符號(hào)char
printf("%hhu\n",'A'+128);   //輸出無符號(hào)char
printf("%hd\n",32767);      //輸出有符號(hào)短整型short int
printf("%hu\n",65535);      //輸出無符號(hào)短整型unsigned short int
printf("%ld\n",0x7fffffffffffffff);     //輸出有符號(hào)長整型long int
printf("%lu\n",0xffffffffffffffff);     //輸出有符號(hào)長整型unsigned long int
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

輸出結(jié)果:

65
193
32767
65535
9223372036854775807
18446744073709551615
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意:
long int到底是32bits還是64bits跟生成的程序是32bits還是64bits一一對(duì)應(yīng),,如果使用g++編譯程序的話,可通過-m32-m64選項(xiàng)分別生成32bits和64bits的程序,。因本人測(cè)試代碼編譯生成的是64bits的程序,,所以long int也就是64btis。

3.轉(zhuǎn)義字符

轉(zhuǎn)義字符在字符串中會(huì)被自動(dòng)轉(zhuǎn)換為相應(yīng)操作命令,。printf()使用的常見轉(zhuǎn)義字符如下:

轉(zhuǎn)義字符 意義
\a 警報(bào)(響鈴)符
\b 回退符
\f 換頁符
\n 換行符
\r 回車符
\t 橫向制表符
\v 縱向制表符
\\ 反斜杠
\” 雙引號(hào)

4.關(guān)于printf緩沖

在printf的實(shí)現(xiàn)中,,在調(diào)用write之前先寫入IO緩沖區(qū),這是一個(gè)用戶空間的緩沖,。系統(tǒng)調(diào)用是軟中斷,,頻繁調(diào)用,需要頻繁陷入內(nèi)核態(tài),,這樣的效率不是很高,,而printf實(shí)際是向用戶空間的IO緩沖寫,在滿足條件的情況下才會(huì)調(diào)用write系統(tǒng)調(diào)用,,減少IO次數(shù),,提高效率。

printf在glibc中默認(rèn)為行緩沖,,遇到以下幾種情況會(huì)刷新緩沖區(qū),,輸出內(nèi)容:
(1)緩沖區(qū)填滿;
(2)寫入的字符中有換行符\n或回車符\r,;
(3)調(diào)用fflush手動(dòng)刷新緩沖區(qū),;
(4)調(diào)用scanf要從輸入緩沖區(qū)中讀取數(shù)據(jù)時(shí),也會(huì)將輸出緩沖區(qū)內(nèi)的數(shù)據(jù)刷新,。

可使用setbuf(stdout,NULL)關(guān)閉行緩沖,,或者setbuf(stdout,uBuff)設(shè)置新的緩沖區(qū),uBuff為自己指定的緩沖區(qū),。也可以使用setvbuf(stdout,NULL,_IOFBF,0);來改變標(biāo)準(zhǔn)輸出為全緩沖,。全緩沖與行緩沖的區(qū)別在于遇到換行符不刷新緩沖區(qū)。

printf在VC++中默認(rèn)關(guān)閉緩沖區(qū),輸出時(shí)會(huì)及時(shí)的輸?shù)狡聊?span role="textbox" aria-readonly="true">[3],。如果顯示開啟緩沖區(qū),,只能設(shè)置全緩沖。因?yàn)槲④涢]源,,所以無法研究printf函數(shù)的實(shí)現(xiàn)源碼,。

Linux和Windows下的緩沖區(qū)管理可見:C的全緩沖、行緩沖和無緩沖,。

5.printf與wprintf不能同時(shí)使用

該小結(jié)寫在2018年1月15日,。兩年后的今日,在網(wǎng)上苦苦搜索尋求答案,,終于解決了之前的疑惑。

在輸出寬字符串時(shí),,發(fā)現(xiàn)將printf和wprintf同時(shí)使用時(shí),,則后使用的函數(shù)沒有輸出。這里建議不要同時(shí)使用printf和wprintf,,以免發(fā)生錯(cuò)誤,。

printf和wprintf不能同時(shí)輸出寬字符串的示例代碼如下:

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(int argc,char* argv[]){
    char test[]="測(cè)試Test";
    setlocale(LC_ALL,"zh_CN.UTF-8");
    wchar_t wtest[]=L"0m~K0m~UTest";
    printf("printf:%S\n",wtest);     //語句1:可正常輸出"測(cè)試Test"
    wprintf(L"wprintf:%S\n",wtest);  //語句2:無任何內(nèi)容輸出
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

上面的代碼中語句1和語句二不能同時(shí)存在,否則只能正常輸出第一個(gè),。也不知道在Windows平臺(tái)是否也存在這種問題,,有興趣的讀者可以嘗試一下。關(guān)于原因,,GNU官方文檔中有明確說明不能同時(shí)使用printf與wprintf,,參見The GNU C Library Section 12.6 Streams in Internationalized Applications,內(nèi)容如下:

It is important to never mix the use of wide and not wide operations on a stream. There are no diagnostics issued. The application behavior will simply be strange or the application will simply crash. 
  • 1

這里是因?yàn)檩敵隽髟诒粍?chuàng)建時(shí),,不存在流定向,,一旦使用了printf(多字節(jié)流)或wprintf(寬字符流)后,就被設(shè)置為對(duì)應(yīng)的流定向,,且無法更改,。可以使用如下函數(shù)獲取當(dāng)前輸出流的流定向,。

//
//@param:stream:文件流,;mode:取值可以>0,,=0或<0
//@ret:<0:流已被設(shè)置為多字節(jié)流定向,;=0:流尚未被設(shè)置,;>0:流已被設(shè)置為寬字符流定向
//
int fwide (FILE* stream, int mode);

//獲取當(dāng)前標(biāo)準(zhǔn)輸出流定向
int ret=fwide(stdout,0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

通過fwide可以設(shè)置當(dāng)前流定向,,前提是未有任何的I/O操作,,也就是當(dāng)前流尚未被設(shè)置任何流定向,。順帶吐槽一下,,不知為何標(biāo)準(zhǔn)庫函數(shù)fwide為何實(shí)現(xiàn)的如此受限,。具體操作如下:

//設(shè)置標(biāo)準(zhǔn)輸出流定向?yàn)槎嘧止?jié)流定向
fwide(stdout,-1);

//設(shè)置標(biāo)準(zhǔn)輸出流定向?yàn)閷捵址鞫ㄏ?fwide(stdout,1);
  • 1
  • 2
  • 3
  • 4
  • 5

既然GNU C存在這個(gè)問題,那該如何解決呢,?這里有兩種辦法:
(1)統(tǒng)一使用一種函數(shù),。
例如:

wprintf(L"%s","a\n");
wprintf(L"b\n");
  • 1
  • 2

printf("a\n");
printf("%ls\n",L"b");
  • 1
  • 2

(2)使用freopen清空流定向。

//重新打開標(biāo)準(zhǔn)輸出流,,清空流定向
FILE* pFile=freopen("/dev/tty","w",stdout);
wprintf(L"wide freopen succeeded\n");

//重新打開標(biāo)準(zhǔn)輸出流,,清空流定向
pFile=freopen("/dev/tty","w",stdout);
printf("narrow freopen succeeded\n");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面可以讓printf與wprintf同時(shí)使用。

6.小結(jié)

耗時(shí)將近兩年,,終于完成了此篇看似基礎(chǔ),,但卻紛繁復(fù)雜的printf()用法。由于時(shí)間和個(gè)人水平有限,,文章不足之處在所難免,,也請(qǐng)讀者批評(píng)指正,不甚感激,。


參考文獻(xiàn)

[1]淺談C中的wprintf和寬字符顯示
[2]printf.C++ reference
[3]Why does printf not flush after the call unless a newline is in the format string?
[4]格式規(guī)范語法:printf 和 wprintf 函數(shù)
[5]The GNU C Library Section 12.6 Streams in Internationalized Applications
[6]fwide.C++ reference

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多