湖南網(wǎng)站制作公司湖南seo網(wǎng)站策劃
標(biāo)準(zhǔn)IO
標(biāo)準(zhǔn) I/O 雖然是對文件 I/O 進(jìn)行了封裝,但事實(shí)上并不僅僅只是如此,標(biāo)準(zhǔn) I/O 會處理很多細(xì)節(jié),譬如分配 stdio 緩沖區(qū)、以優(yōu)化的塊長度執(zhí)行 I/O 等,這些處理使用戶不必?fù)?dān)心如何選擇使用正確的塊長度。I/O 庫函數(shù)是構(gòu)建于文件 I/O(open()、 read()、 write()、 lseek()、 close()等)這些系統(tǒng)調(diào)用之上的,譬如標(biāo)準(zhǔn) I/O 庫函數(shù) fopen()就利用系統(tǒng)調(diào)用 open()來執(zhí)行打開文件的操作、 fread()利用系統(tǒng)調(diào)用 read()來執(zhí)行讀文件操作、 fwrite()則利用系統(tǒng)調(diào)用 write()來執(zhí)行寫文件操作等等。那既然如此,為何還需要設(shè)計(jì)標(biāo)準(zhǔn) I/O 庫?直接使用文件 I/O 系統(tǒng)調(diào)用不是更好嗎?事實(shí)上,并非如此, 在第一章中我們也提到過,設(shè)計(jì)庫函數(shù)是為了提供比底層系統(tǒng)調(diào)用更為方便、好用的調(diào)用接口, 雖然標(biāo)準(zhǔn) I/O 構(gòu)建于文件 I/O 之上, 但標(biāo)準(zhǔn) I/O 卻有它自己的優(yōu)勢,標(biāo)準(zhǔn) I/O 和文件 I/O 的區(qū)別如下:
雖然標(biāo)準(zhǔn) I/O 和文件 I/O 都是 C 語言函數(shù),但是標(biāo)準(zhǔn) I/O 是標(biāo)準(zhǔn) C 庫函數(shù),而文件 I/O 則是 Linux系統(tǒng)調(diào)用;
標(biāo)準(zhǔn) I/O 是由文件 I/O 封裝而來,標(biāo)準(zhǔn) I/O 內(nèi)部實(shí)際上是調(diào)用文件 I/O 來完成實(shí)際操作的;
-
可移植性:標(biāo)準(zhǔn) I/O 相比于文件 I/O 具有更好的可移植性,通常對于不同的操作系統(tǒng),其內(nèi)核向應(yīng)用層提供的系統(tǒng)調(diào)用往往都是不同,譬如系統(tǒng)調(diào)用的定義、功能、參數(shù)列表、返回值等往往都是不一樣的;而對于標(biāo)準(zhǔn) I/O 來說,由于很多操作系統(tǒng)都實(shí)現(xiàn)了標(biāo)準(zhǔn) I/O 庫,標(biāo)準(zhǔn) I/O 庫在不同的操作系統(tǒng)之間其接口定義幾乎是一樣的,所以標(biāo)準(zhǔn) I/O 在不同操作系統(tǒng)之間相比于文件 I/O 具有更好的可移植性。
-
性能、效率: 標(biāo)準(zhǔn) I/O 庫在用戶空間維護(hù)了自己的 stdio 緩沖區(qū), 所以標(biāo)準(zhǔn) I/O 是帶有緩存的,而文件 I/O 在用戶空間是不帶有緩存的,所以在性能、效率上,標(biāo)準(zhǔn) I/O 要優(yōu)于文件 I/O。
對于標(biāo)準(zhǔn) I/O 庫函數(shù)來說,它們的操作是圍繞 FILE 指針進(jìn)行的,當(dāng)使用標(biāo)準(zhǔn) I/O 庫函數(shù)打開或創(chuàng)建一個(gè)文件時(shí),會返回一個(gè)指向 FILE 類型對象的指針(FILE *) ,使用該 FILE 指針與被打開或創(chuàng)建的文件相關(guān)聯(lián),然后該 FILE 指針就用于后續(xù)的標(biāo)準(zhǔn) I/O 操作(使用標(biāo)準(zhǔn) I/O 庫函數(shù)進(jìn)行 I/O 操作),所以由此可知,FILE 指針的作用相當(dāng)于文件描述符,只不過 FILE 指針用于標(biāo)準(zhǔn) I/O 庫函數(shù)中、而文件描述符則用于文件I/O 系統(tǒng)調(diào)用中。FILE 是一個(gè)結(jié)構(gòu)體數(shù)據(jù)類型,它包含了標(biāo)準(zhǔn) I/O 庫函數(shù)為管理文件所需要的所有信息,包括用于實(shí)際I/O 的文件描述符、指向文件緩沖區(qū)的指針、緩沖區(qū)的長度、當(dāng)前緩沖區(qū)中的字節(jié)數(shù)以及出錯標(biāo)志等。 FILE數(shù)據(jù)結(jié)構(gòu)定義在標(biāo)準(zhǔn) I/O 庫函數(shù)頭文件 stdio.h 中。
所謂標(biāo)準(zhǔn)輸入設(shè)備指的就是計(jì)算機(jī)系統(tǒng)的標(biāo)準(zhǔn)的輸入設(shè)備,通常指的是計(jì)算機(jī)所連接的鍵盤;而標(biāo)準(zhǔn)輸出設(shè)備指的是計(jì)算機(jī)系統(tǒng)中用于輸出標(biāo)準(zhǔn)信息的設(shè)備,通常指的是計(jì)算機(jī)所連接的顯示器;標(biāo)準(zhǔn)錯誤設(shè)備則指的是計(jì)算機(jī)系統(tǒng)中用于顯示錯誤信息的設(shè)備,通常也指的是顯示器設(shè)備。
用戶通過標(biāo)準(zhǔn)輸入設(shè)備與系統(tǒng)進(jìn)行交互, 進(jìn)程將從標(biāo)準(zhǔn)輸入(stdin)文件中得到輸入數(shù)據(jù),將正常輸出數(shù)據(jù)(譬如程序中 printf 打印輸出的字符串) 輸出到標(biāo)準(zhǔn)輸出(stdout) 文件,而將錯誤信息(譬如函數(shù)調(diào)用報(bào)錯打印的信息)輸出到標(biāo)準(zhǔn)錯誤(stderr) 文件。標(biāo)準(zhǔn)輸出文件和標(biāo)準(zhǔn)錯誤文件都對應(yīng)終端的屏幕,而標(biāo)準(zhǔn)輸入文件則對應(yīng)于鍵盤。每個(gè)進(jìn)程啟動之后都會默認(rèn)打開標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出以及標(biāo)準(zhǔn)錯誤, 得到三個(gè)文件描述符, 即 0、 1、2, 其中 0 代表標(biāo)準(zhǔn)輸入、 1 代表標(biāo)準(zhǔn)輸出、 2 代表標(biāo)準(zhǔn)錯誤;
在應(yīng)用編程中可以使用宏 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 分別代表 0、 1、 2,這些宏定義在 unistd.h 頭文件中:
/* Standard file descriptors. */ #define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO1 /* Standard output. */ #define STDERR_FILENO2 /* Standard error output. */
0、 1、 2 這三個(gè)是文件描述符,只能用于文件 I/O(read()、 write()等),那么在標(biāo)準(zhǔn) I/O 中,自然是無法使用文件描述符來對文件進(jìn)行 I/O 操作的,它們需要圍繞 FILE 類型指針來進(jìn)行,在 stdio.h 頭文件中有相應(yīng)的定義,如下:
/* Standard streams. */ extern struct _IO_FILE *stdin; /* Standard input stream. */ extern struct _IO_FILE *stdout; /* Standard output stream. */ extern struct _IO_FILE *stderr; /* Standard error output stream. */ /* C89/C99 say they're macros. Make them happy. */ #define stdin stdin #define stdout stdou t#define stderr stderr
Tips: struct _IO_FILE 結(jié)構(gòu)體就是 FILE 結(jié)構(gòu)體,使用了 typedef 進(jìn)行了重命名。所以,在標(biāo)準(zhǔn) I/O 中,可以使用 stdin、 stdout、 stderr 來表示標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯誤。
用庫函數(shù)fopen()打開或創(chuàng)建文件, fopen()函數(shù)原型如下所示:
#include <stdio.h> FILE *fopen(const char *path, const char *mode);
使用該函數(shù)需要包含頭文件 stdio.h。函數(shù)參數(shù)和返回值含義如下:
-
path: 參數(shù) path 指向文件路徑,可以是絕對路徑、也可以是相對路徑。
-
mode: 參數(shù) mode 指定了對該文件的讀寫權(quán)限,是一個(gè)字符串,稍后介紹。
-
返回值: 調(diào)用成功返回一個(gè)指向 FILE 類型對象的指針(FILE *),該指針與打開或創(chuàng)建的文件相關(guān)聯(lián),后續(xù)的標(biāo)準(zhǔn) I/O 操作將圍繞 FILE 指針進(jìn)行。 如果失敗則返回 NULL,并設(shè)置 errno 以指示錯誤原因。參數(shù) mode 字符串類型,可取值為如下值之一:
mode | 說明 | flags 參數(shù)取值 |
---|---|---|
r | 以只讀方式打開文件。 | O_RDONLY |
r+ | 以可讀、可寫方式打開文件。 | O_RDWR |
w | 以只寫方式打開文件;如果文件存在,將文件長度截?cái)酁?;如果文件不存在,則創(chuàng)建文件。 | O_WRONLY | O_CREAT | O_TRUNC |
w+ | 以可讀、可寫方式打開文件;如果文件存在,將文件長度截?cái)酁?;如果文件不存在,則創(chuàng)建文件。 | O_RDWR |O_CREAT O_TRUNC |
a | 以只寫方式打開文件,進(jìn)行追加內(nèi)容(在文件末尾寫入);如果文件不存在,則創(chuàng)建文件。 | O_WRONLY | O_CREAT | O_APPEND |
a+ | 以可讀、可寫方式打開文件,進(jìn)行追加內(nèi)容(在文件末尾寫入);如果文件不存在,則創(chuàng)建文件。 | O_RDWR | O_CREAT | O_APPEND |
讀文件和寫文件
當(dāng)使用 fopen()庫函數(shù)打開文件之后,接著我們便可以使用 fread()和 fwrite()庫函數(shù)對文件進(jìn)行讀、寫操作了,函數(shù)原型如下所示:
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
庫函數(shù) fread()用于讀取文件數(shù)據(jù),其參數(shù)和返回值含義如下:
-
ptr: fread()將讀取到的數(shù)據(jù)存放在參數(shù) ptr 指向的緩沖區(qū)中;
-
size: fread()從文件讀取 nmemb 個(gè)數(shù)據(jù)項(xiàng),每一個(gè)數(shù)據(jù)項(xiàng)的大小為 size 個(gè)字節(jié),所以總共讀取的數(shù)據(jù)大小為 nmemb * size 個(gè)字節(jié)。
-
nmemb: 參數(shù) nmemb 指定了讀取數(shù)據(jù)項(xiàng)的個(gè)數(shù)。stream: FILE 指針。
-
返回值: 調(diào)用成功時(shí)返回讀取到的數(shù)據(jù)項(xiàng)的數(shù)目(數(shù)據(jù)項(xiàng)數(shù)目并不等于實(shí)際讀取的字節(jié)數(shù),除非參數(shù)size 等于 1);如果發(fā)生錯誤或到達(dá)文件末尾,則 fread()返回的值將小于參數(shù) nmemb,那么到底發(fā)生了錯誤還是到達(dá)了文件末尾, fread()不能區(qū)分文件結(jié)尾和錯誤, 究竟是哪一種情況,此時(shí)可以使用 ferror()或 feof()函數(shù)來判斷
庫函數(shù) fwrite()用于將數(shù)據(jù)寫入到文件中,其參數(shù)和返回值含義如下:
-
ptr: 將參數(shù) ptr 指向的緩沖區(qū)中的數(shù)據(jù)寫入到文件中。
-
size: 參數(shù) size 指定了每個(gè)數(shù)據(jù)項(xiàng)的字節(jié)大小,與 fread()函數(shù)的 size 參數(shù)意義相同。
-
nmemb: 參數(shù) nmemb 指定了寫入的數(shù)據(jù)項(xiàng)個(gè)數(shù),與 fread()函數(shù)的 nmemb 參數(shù)意義相同。stream: FILE 指針。
-
返回值: 調(diào)用成功時(shí)返回寫入的數(shù)據(jù)項(xiàng)的數(shù)目(數(shù)據(jù)項(xiàng)數(shù)目并不等于實(shí)際寫入的字節(jié)數(shù),除非參數(shù) size等于 1);如果發(fā)生錯誤,則 fwrite()返回的值將小于參數(shù) nmemb(或者等于 0)。
由此可知,庫函數(shù) fread()、 fwrite()中指定讀取或?qū)懭霐?shù)據(jù)大小的方式與系統(tǒng)調(diào)用 read()、 write()不同,前者通過 nmemb(數(shù)據(jù)項(xiàng)個(gè)數(shù)) *size(每個(gè)數(shù)據(jù)項(xiàng)的大小)的方式來指定數(shù)據(jù)大小,而后者則直接通過一個(gè) size 參數(shù)指定數(shù)據(jù)大小。譬如要將一個(gè) struct mystr 結(jié)構(gòu)體數(shù)據(jù)寫入到文件中:
-
可按如下方式寫入:fwrite(buf, sizeof(struct mystr), 1, file);
-
當(dāng)然也可以按如下方式寫:fwrite(buf, 1, sizeof(struct mystr), file);
庫函數(shù) fseek()的作用類似于系統(tǒng)調(diào)用 lseek(), 用于設(shè)置文件讀寫位置偏移量, lseek()用于文件 I/O,而庫函數(shù) fseek()則用于標(biāo)準(zhǔn) I/O,其函數(shù)原型如下所示:
#include <stdio.h>int fseek(FILE *stream, long offset, int whence);
函數(shù)參數(shù)和返回值含義如下:
-
stream: FILE 指針。
-
offset: 與 lseek()函數(shù)的 offset 參數(shù)意義相同。
-
whence: 與 lseek()函數(shù)的 whence 參數(shù)意義相同。
-
返回值: 成功返回 0;發(fā)生錯誤將返回-1,并且會設(shè)置 errno 以指示錯誤原因; 與 lseek()函數(shù)的返回值意義不同,這里要注意!調(diào)用庫函數(shù) fread()、 fwrite()讀寫文件時(shí),文件的讀寫位置偏移量會自動遞增,使用 fseek()可手動設(shè)置文件當(dāng)前的讀寫位置偏移量。
-
譬如將文件的讀寫位置移動到文件開頭處:fseek(file, 0, SEEK_SET);
-
將文件的讀寫位置移動到文件末尾:fseek(file, 0, SEEK_END);
-
將文件的讀寫位置移動到 100 個(gè)字節(jié)偏移量處:fseek(file, 100, SEEK_SET);
調(diào)用 fread()讀取數(shù)據(jù)時(shí),如果返回值小于參數(shù) nmemb 所指定的值,表示發(fā)生了錯誤或者已經(jīng)到了文件末尾(文件結(jié)束 end-of-file),但 fread()無法具體確定是哪一種情況; 在這種情況下,可以通過判斷錯誤標(biāo)志或 end-of-file 標(biāo)志來確定具體的情況。feof()函數(shù)庫函數(shù) feof()用于測試參數(shù) stream 所指文件的 end-of-file 標(biāo)志,如果 end-of-file 標(biāo)志被設(shè)置了,則調(diào)用feof()函數(shù)將返回一個(gè)非零值,如果 end-of-file 標(biāo)志沒有被設(shè)置,則返回 0。
#include <stdio.h> int feof(FILE *stream);
當(dāng)文件的讀寫位置移動到了文件末尾時(shí), end-of-file 標(biāo)志將會被設(shè)置。庫函數(shù) ferror()用于測試參數(shù) stream 所指文件的錯誤標(biāo)志,如果錯誤標(biāo)志被設(shè)置了,則調(diào)用 ferror()函數(shù)將返回一個(gè)非零值,如果錯誤標(biāo)志沒有被設(shè)置,則返回 0。其函數(shù)原型如下所示:
#include <stdio.h> int ferror(FILE *stream);
C 庫函數(shù)提供了 5 個(gè)格式化輸出函數(shù),包括: printf()、 fprintf()、 dprintf()、 sprintf()、 snprintf(),其函數(shù)定義如下所示:
#include <stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int dprintf(int fd, const char *format, ...); int sprintf(char *buf, const char *format, ...); int snprintf(char *buf, size_t size, const char *format, ...);
這 5 個(gè)函數(shù)都是可變參函數(shù),它們都有一個(gè)共同的參數(shù) format,這是一個(gè)字符串,稱為格式控制字符串,用于指定后續(xù)的參數(shù)如何進(jìn)行格式轉(zhuǎn)換, 所以才把這些函數(shù)稱為格式化輸出,因?yàn)樗鼈兛梢砸哉{(diào)用者指定的格式進(jìn)行轉(zhuǎn)換輸出; 學(xué)習(xí)這些函數(shù)的重點(diǎn)就是掌握這個(gè)格式控制字符串 format 的書寫格式以及它們所代表的意義, 每個(gè)函數(shù)除了固定參數(shù)之外,還可攜帶 0 個(gè)或多個(gè)可變參數(shù)。printf()函數(shù)
用于將格式化數(shù)據(jù)寫入到標(biāo)準(zhǔn)輸出; dprintf()和 fprintf()函數(shù)用于將格式化數(shù)據(jù)寫入到指定的文件中,兩者不同之處在于, fprintf()使用 FILE 指針指定對應(yīng)的文件、而 dprintf()則使用文件描述符 fd 指定對應(yīng)的文件; sprintf()、 snprintf()函數(shù)可將格式化的數(shù)據(jù)存儲在用戶指定的緩沖區(qū) buf 中。printf()函數(shù)前面章節(jié)內(nèi)容編寫的示例代碼中多次使用了該函數(shù),用于將程序中的字符串信息輸出顯示到終端(也就是標(biāo)準(zhǔn)輸出),它是一個(gè)可變參函數(shù),除了一個(gè)固定參數(shù) format外,后面還可攜帶 0 個(gè)或多個(gè)參數(shù)。函數(shù)調(diào)用成功返回打印輸出的字符數(shù);失敗將返回一個(gè)負(fù)值!打印“Hello World”:printf("Hello World!\n");打印數(shù)字 5:printf("%d\n", 5);
fprintf()可將格式化數(shù)據(jù)寫入到由 FILE 指針指定的文件中,譬如將字符串“Hello World”寫入到標(biāo)準(zhǔn)錯誤:fprintf(stderr, "Hello World!\n");向標(biāo)準(zhǔn)錯誤寫入數(shù)字 5:fprintf(stderr, "%d\n", 5);函數(shù)調(diào)用成功返回寫入到文件中的字符數(shù);失敗將返回一個(gè)負(fù)值!
dprintf()可將格式化數(shù)據(jù)寫入到由文件描述符 fd 指定的文件中,譬如將字符串“Hello World”寫入到標(biāo)準(zhǔn)錯誤:dprintf(STDERR_FILENO, "Hello World!\n");向標(biāo)準(zhǔn)錯誤寫入數(shù)字 5:dprintf(STDERR_FILENO, "%d\n", 5);函數(shù)調(diào)用成功返回寫入到文件中的字符數(shù);失敗將返回一個(gè)負(fù)值!
sprintf()函數(shù):sprintf()函數(shù)將格式化數(shù)據(jù)存儲在由參數(shù) buf 所指定的緩沖區(qū)中, 譬如將字符串“Hello World”存放在緩沖區(qū)中:
char buf[100];sprintf(buf, "Hello World!\n");
當(dāng)然這種用法并沒有意義,事實(shí)上,我們一般會使用這個(gè)函數(shù)進(jìn)行格式化轉(zhuǎn)換,并將轉(zhuǎn)換后的字符串存放在緩沖區(qū)中,譬如將數(shù)字 100 轉(zhuǎn)換為字符串"100",將轉(zhuǎn)換后得到的字符串存放在 buf 中:
char buf[20] = {0}; sprintf(buf, "%d", 100);
sprintf()函數(shù)會在字符串尾端自動加上一個(gè)字符串終止字符'\0'。
需要注意的是, sprintf()函數(shù)可能會造成由參數(shù) buf 指定的緩沖區(qū)溢出,調(diào)用者有責(zé)任確保該緩沖區(qū)足夠大,因?yàn)榫彌_區(qū)溢出會造成程序不穩(wěn)定甚至安全隱患!函數(shù)調(diào)用成功返回寫入到 buf 中的字節(jié)數(shù);失敗將返回一個(gè)負(fù)值!snprintf()函數(shù)sprintf()函數(shù)可能會發(fā)生緩沖區(qū)溢出的問題,存在安全隱患,為了解決這個(gè)問題,引入了 snprintf()函數(shù);在該函數(shù)中,使用參數(shù) size 顯式的指定緩沖區(qū)的大小,如果寫入到緩沖區(qū)的字節(jié)數(shù)大于參數(shù) size 指定的大小,超出的部分將會被丟棄!如果緩沖區(qū)空間足夠大, snprintf()函數(shù)就會返回寫入到緩沖區(qū)的字符數(shù),與sprintf()函數(shù)相同,也會在字符串末尾自動添加終止字符'\0'。若發(fā)生錯誤, snprintf()將返回一個(gè)負(fù)值!
以上 5 個(gè)函數(shù)中的 format 參數(shù)應(yīng)該怎么寫,把這個(gè)參數(shù)稱為格式控制字符串,顧名思義,首先它是一個(gè)字符串的形式,其次它能夠控制后續(xù)變參的格式轉(zhuǎn)換。格式控制字符串由兩部分組成:普通字符(非%字符) 和轉(zhuǎn)換說明。普通字符會進(jìn)行原樣輸出,每個(gè)轉(zhuǎn)換說明都會對應(yīng)后續(xù)的一個(gè)參數(shù),通常有幾個(gè)轉(zhuǎn)換說明就需要提供幾個(gè)參數(shù)(除固定參數(shù)之外的參數(shù)), 使之一一對應(yīng),用于控制對應(yīng)的參數(shù)如何進(jìn)行轉(zhuǎn)換。如下所示:printf("轉(zhuǎn)換說明 1 轉(zhuǎn)換說明 2 轉(zhuǎn)換說明 3", arg1, arg2, arg3);這里只是以 printf()函數(shù)舉個(gè)例子,實(shí)際上并不這樣用。三個(gè)轉(zhuǎn)換說明與參數(shù)進(jìn)行一一對應(yīng),按照順序方式一一對應(yīng)。每個(gè)轉(zhuǎn)換說明都是以%字符開頭,其格式如下所示(使用[ ]括起來的部分是可選的) :
%[flags][width][.precision][length]type
-
flags: 標(biāo)志,可包含 0 個(gè)或多個(gè)標(biāo)志;
-
width: 輸出最小寬度,表示轉(zhuǎn)換后輸出字符串的最小寬度;precision: 精度,前面有一個(gè)點(diǎn)號" . ";
-
length: 長度修飾符;
-
type: 轉(zhuǎn)換類型,指定待轉(zhuǎn)換數(shù)據(jù)的類型。
-
可以看到,只有%和 type 字段是必須的,其余都是可選的。
首先說明 type(類型), 因?yàn)轭愋褪歉袷娇刂谱址闹刂兄?#xff0c;是必不可少的組成部分,其它的字段都是可選的, type 用于指定輸出數(shù)據(jù)的類型, type 字段使用一個(gè)字符(字母字符)來表示:
字符 | 對應(yīng)數(shù)據(jù)類型 | 含義 | 示例說明 |
---|---|---|---|
d/i | int | 輸出有符號十進(jìn)制表示的整數(shù),i 是老式寫法 | printf("%d\n", 123); 輸出: 123 |
o | unsigned int | 輸出無符號八進(jìn)制表示的整數(shù)(默認(rèn)不輸出前綴0,可在 # 標(biāo)志下輸出前綴0) | printf("%o\n", 123); 輸出: 173 |
u | unsigned int | 輸出無符號十進(jìn)制表示的整數(shù) | printf("%u\n", 123); 輸出: 123 |
x/X | unsigned int | 輸出無符號十六進(jìn)制表示的整數(shù),x 和 X 區(qū)別在于字母大小寫 | printf("%x\n", 123); 輸出: 7b printf("%X\n", 123); 輸出: 7B |
f/F | double | 輸出浮點(diǎn)數(shù),f 和 F 區(qū)別在于字母大小寫,默認(rèn)保留小數(shù)點(diǎn)后 6 位數(shù) | printf("%f\n", 520.1314); 輸出: 520.131400 printf("%F\n", 520.1314); 輸出: 520.131400 |
e/E | double | 輸出以科學(xué)計(jì)數(shù)法表示的浮點(diǎn)數(shù),e 和 E 區(qū)別在于字母大小寫 | printf("%e\n", 520.1314); 輸出: 5.201314e+02 printf("%E\n", 520.1314); 輸出: 5.201314E+02 |
g | double | 根據(jù)數(shù)值的長度,選擇以最短方式輸出,%f/%e | printf("%g %g\n", 0.000000123, 0.123); 輸出: 1.23e-07 0.123 |
G | double | 根據(jù)數(shù)值的長度,選擇以最短方式輸出,%F/%E | printf("%G %G\n", 0.000000123, 0.123); 輸出: 1.23E-07 0.123 |
s | char * | 字符串,輸出字符串中的字符直到終止字符 \0 | printf("%s\n", "Hello World"); 輸出: Hello World |
p | void * | 輸出十六進(jìn)制表示的指針 | printf("%p\n", "Hello World"); 輸出: 0x400624 |
c | char | 字符型,將輸入的數(shù)字轉(zhuǎn)換為對應(yīng)的 ASCII 字符輸出 | printf("%c\n", 64); 輸出: A |
flags字段的含義如下:
字符 | 名稱 | 作用 |
---|---|---|
# | 井號 | 對于 o 類型,輸出字符串增加前綴 0;對于 x 或 X 類型,輸出前綴 0x 或 0X 。對于浮點(diǎn)數(shù)類型,強(qiáng)制輸出小數(shù)點(diǎn)。 |
0 | 數(shù)字 0 | 當(dāng)輸出數(shù)字(非 c 或 s 類型)時(shí),在輸出前補(bǔ) 0,直到達(dá)到指定最小寬度。 |
- | 減號 | 左對齊輸出,若寬度不足則在右邊填充空格。若同時(shí)指定 0 和 - ,- 會覆蓋 0 。 |
' ' | 空格 | 輸出正數(shù)時(shí),在數(shù)字前加一個(gè)空格,負(fù)數(shù)則加負(fù)號 - 。 |
+ | 加號 | 輸出時(shí)無論正數(shù)還是負(fù)數(shù),前面都帶符號。正數(shù)帶 + ,負(fù)數(shù)帶 - 。+ 會覆蓋 ' ' (空格)。 |
寬度類型 | 描述 | 示例 |
---|---|---|
數(shù)字 | 指定輸出的最小寬度,若實(shí)際輸出位數(shù)小于指定寬度,前面會補(bǔ)充空格或 0 。 | printf("%06d", 1000); 輸出: 001000 |
* | 不顯示寬度數(shù)值,寬度由參數(shù)列表中的值指定。 | printf("%0*d", 6, 1000); 輸出: 001000 |
描述 | 類型 | 示例 |
---|---|---|
數(shù)字 | 整型(d , i , o , u , x , X ) | 對于整型,指定輸出的最小數(shù)字位數(shù),不足時(shí)補(bǔ)前導(dǎo)零。 例如 printf("%8.5d", 100); 輸出: 00100 |
浮點(diǎn)型(a , A , e , E , f , F ) | 對于浮點(diǎn)數(shù),指定小數(shù)點(diǎn)后數(shù)字的個(gè)數(shù)。默認(rèn)6位。 例如 printf("%.8f", 520.1314); 輸出: 520.13140000 | |
g , G | 對于 g 和 G ,表示最大有效數(shù)字位數(shù)。 | |
字符串 | s | 指定最大輸出字符數(shù),超過則截?cái)唷?例如 printf("%.5s", "hello world"); 輸出: hello |
* | 星號 | 精度由參數(shù)列表指定,例如 printf("%.*s", 5, "hello world"); 輸出: hello |
長度修飾符指明待轉(zhuǎn)換數(shù)據(jù)的長度,因?yàn)?type 字段指定的的類型只有 int、unsigned int 以及 double 等幾種數(shù)據(jù)類型,但是C 語言內(nèi)置的數(shù)據(jù)類型不止這幾種,譬如有 16bit 的 short、unsigned short,8bit 的char、unsigned char,也有64bit 的 long long 等,為了能夠區(qū)別不同長度的數(shù)據(jù)類型,于是乎,長度修飾符(length)應(yīng)運(yùn)而生,成為轉(zhuǎn)換說明的一部分。 length 長度修飾符也是使用字符(字母字符)來表示,結(jié)合type 字段以確定不同長度的數(shù)據(jù)類型:
type | length | 描述 |
---|---|---|
d , i | none | int 類型,輸出有符號十進(jìn)制整數(shù)。 |
u , o , x , X | none | unsigned int 類型,輸出無符號十進(jìn)制、八進(jìn)制、十六進(jìn)制整數(shù)。 |
f , F , e , E , g , G | none | double 類型,輸出浮點(diǎn)數(shù),使用小數(shù)表示或科學(xué)計(jì)數(shù)法。 |
c | none | char 類型,輸出一個(gè)字符。 |
s | none | char * 類型,輸出字符串。 |
p | none | void * 類型,輸出指針的十六進(jìn)制表示。 |
hh | signed char , unsigned char | signed char 或 unsigned char 類型,輸出字符。 |
h | short int , unsigned short int | short int 或 unsigned short int 類型,輸出整數(shù)。 |
l | long int , unsigned long int | long int 或 unsigned long int 類型,輸出整數(shù)。 |
wint_t | wchar_t | 寬字符類型(wint_t 或 wchar_t ),用于寬字符處理。 |
ll | long long int , unsigned long long int | long long int 或 unsigned long long int 類型,輸出整數(shù)。 |
L | long double | long double 類型,輸出浮點(diǎn)數(shù)。 |
j | intmax_t , uintmax_t | intmax_t 或 uintmax_t 類型,輸出整數(shù)。 |
z | size_t , ssize_t | size_t 或 ssize_t 類型,輸出無符號或有符號整數(shù)。 |
t | ptrdiff_t | ptrdiff_t 類型,表示指針差值。 |
格式化輸入是類似的,這里不加以贅述了。