[单刷APUE系列]第五章——标准I/O库
目錄
[單刷APUE系列]第一章——Unix基礎(chǔ)知識(shí)[1]
[單刷APUE系列]第一章——Unix基礎(chǔ)知識(shí)[2]
[單刷APUE系列]第二章——Unix標(biāo)準(zhǔn)及實(shí)現(xiàn)
[單刷APUE系列]第三章——文件I/O
[單刷APUE系列]第四章——文件和目錄[1]
[單刷APUE系列]第四章——文件和目錄[2]
[單刷APUE系列]第五章——標(biāo)準(zhǔn)I/O庫(kù)
[單刷APUE系列]第六章——系統(tǒng)數(shù)據(jù)文件和信息
[單刷APUE系列]第七章——進(jìn)程環(huán)境
[單刷APUE系列]第八章——進(jìn)程控制[1]
[單刷APUE系列]第八章——進(jìn)程控制[2]
[單刷APUE系列]第九章——進(jìn)程關(guān)系
[單刷APUE系列]第十章——信號(hào)[1]
流和FILE對(duì)象
在學(xué)習(xí)C語(yǔ)言的時(shí)候,肯定也對(duì)標(biāo)準(zhǔn)I/O庫(kù)有所了解,這個(gè)庫(kù)是由ISO C標(biāo)注制定的,前面也說過,ISO C被包含在SUS標(biāo)準(zhǔn)中,所以SUS在ISO C的標(biāo)準(zhǔn)上,又進(jìn)行了擴(kuò)充。
標(biāo)準(zhǔn)I/O庫(kù)最大的好處就是不需要再和底層內(nèi)核調(diào)用打交道了,非常方便的就能跨平臺(tái)使用,在前面幾節(jié)中,大家也對(duì)I/O各種繁瑣的細(xì)節(jié)也有些頭暈,而標(biāo)準(zhǔn)I/O庫(kù)就很便于使用,但是如果不對(duì)底層有所了解,在使用的時(shí)候也會(huì)出現(xiàn)問題的。
在第三章中,所有的內(nèi)容都是由`stat'引出,然后圍繞著文件描述符進(jìn)行講述,但是標(biāo)準(zhǔn)I/O庫(kù)則是圍繞著流來進(jìn)行。
眾所周知,現(xiàn)有的所有字符,可以分為ASCII字符和寬字符,所以標(biāo)準(zhǔn)I/O函數(shù)是圍繞著單字符和寬字符的。就像是汽車和火車,汽車只能在馬路上跑,火車只能在鐵軌上跑,當(dāng)一個(gè)流被創(chuàng)建的時(shí)候,是不能確定是寬字符還是單字節(jié)的,只有后續(xù)I/O操作才會(huì)確定下來。
如果流的方向被確定了,那么fwide函數(shù)不會(huì)改變流的方向。否則,fwide會(huì)設(shè)置流的方向
如果mode小于0,流將被設(shè)置為字節(jié)方向;如果mode大于0,流將被設(shè)置為寬方向。如果mode為0,則不改變方向
無論是否改變,返回值都會(huì)存在,用于確定流的方向
標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤
就像前文提到的一樣,進(jìn)程自動(dòng)會(huì)打開三個(gè)文件描述符。我們知道文件描述符和文件關(guān)聯(lián),就像是預(yù)定義了三個(gè)文件描述符STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,標(biāo)準(zhǔn)庫(kù)也提供了預(yù)定義的stdin、stdout、stderr文件指針。
緩沖
前面提到過,Unix系統(tǒng)自己提供的是不帶緩沖的I/O函數(shù)。緩沖的意義就是為了減少調(diào)用read和write的次數(shù),標(biāo)準(zhǔn)庫(kù)對(duì)每個(gè)流都自動(dòng)管理緩沖,這樣開發(fā)者就不會(huì)為了緩沖區(qū)到底用多大、跨平臺(tái)標(biāo)準(zhǔn)不一致而苦惱了,但是也應(yīng)當(dāng)注意到,標(biāo)準(zhǔn)I/O函數(shù)庫(kù)的提出已經(jīng)經(jīng)過很多年了,而且?guī)缀鯖]有改動(dòng)過,所以就算是緩沖,也有很多的困擾出現(xiàn)。
在前面提到過,Unix系統(tǒng)實(shí)現(xiàn)在內(nèi)核中都設(shè)有高速緩沖,大多數(shù)的磁盤IO都通過緩沖區(qū)進(jìn)行,為了保證實(shí)際文件系統(tǒng)的一致性,系統(tǒng)還提供了一些磁盤同步函數(shù)。對(duì)于標(biāo)準(zhǔn)IO來說,它有三種緩沖類型
全緩沖,或者說,叫做塊緩沖。相關(guān)標(biāo)準(zhǔn)IO函數(shù)會(huì)先使用malloc來獲得固定大小的緩沖區(qū),每當(dāng)緩沖區(qū)被填滿后就會(huì)進(jìn)行實(shí)際的磁盤寫入,開發(fā)者也可以手動(dòng)調(diào)用fflush函數(shù)來強(qiáng)制將緩沖區(qū)寫入磁盤,請(qǐng)記住,這個(gè)是標(biāo)準(zhǔn)C函數(shù)庫(kù)的函數(shù),和前面提到的Unix系統(tǒng)提供的磁盤同步系統(tǒng)調(diào)用時(shí)兩碼事
行緩沖。在輸入輸出時(shí)遇到換行符,自動(dòng)進(jìn)行IO寫入。我們知道,標(biāo)準(zhǔn)IO庫(kù)的緩沖區(qū)是固定的,所以只要填滿了緩沖區(qū),即使沒有遇上換行符也會(huì)執(zhí)行IO操作
不帶緩沖。就如同Unix系統(tǒng)提供的write函數(shù)一樣,標(biāo)準(zhǔn)庫(kù)不對(duì)字符進(jìn)行緩沖存儲(chǔ)
需要注意的是,stderr通常是不帶緩沖的,因?yàn)殄e(cuò)誤信息通常需要得到立即的輸出處理。
ISO C標(biāo)準(zhǔn)只規(guī)定了
當(dāng)且僅當(dāng)標(biāo)準(zhǔn)輸入輸出不指向交互式設(shè)備時(shí),他們才是全緩沖的
標(biāo)準(zhǔn)錯(cuò)誤絕對(duì)不是全緩沖
非常曖昧的定義,結(jié)果開發(fā)者還得自己注意不同平臺(tái)的實(shí)現(xiàn)。但是目前來說,大部分的系統(tǒng)規(guī)定都是一樣的
標(biāo)準(zhǔn)錯(cuò)誤不帶緩沖
指向終端的流是行緩沖,其他則是全緩沖
從Mac OS X的系統(tǒng)手冊(cè)上可以找到上面提到的東西
Three types of buffering are available: unbuffered, block buffered, and line buffered. When an output stream is unbuffered, information appears on the des-tination file or terminal as soon as written; when it is block buffered, many characters are saved up and written as a block; when it is line buffered,
characters are saved up until a newline is output or input is read from any stream attached to a terminal device (typically stdin). The function fflush(3) may be used to force the block out early. (See fclose(3).)
Normally, all files are block buffered. When the first I/O operation occurs on a file, malloc(3) is called and an optimally-sized buffer is obtained. If a stream refers to a terminal (as stdout normally does), it is line buffered. The standard error stream stderr is always unbuffered.
下面是更改緩沖類型的函數(shù)
void setbuf(FILE *restrict stream, char *restrict buf); int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size);setbuf函數(shù)用于打開關(guān)閉緩沖機(jī)制,將一個(gè)長(zhǎng)度為BUFSIZ的緩沖區(qū)傳入?yún)?shù),就會(huì)打開緩沖區(qū),而傳入null則會(huì)關(guān)閉緩沖區(qū)。
setvbuf函數(shù)功能十分強(qiáng)大,我們可以精確的說明緩沖類型
_IONBF->unbuffered 無緩沖
_IOLBF->line buffered 行緩沖
_IOFBF->fully buffered 全緩沖
一個(gè)不帶緩沖的流可以忽略type和size參數(shù),當(dāng)一個(gè)緩沖傳入的buf是null時(shí),系統(tǒng)會(huì)自動(dòng)分配緩沖區(qū)。
其實(shí)除了上面兩個(gè)函數(shù)外,還有兩個(gè)函數(shù),但是由于原著未講,所以這里也不提及。
其實(shí)setbuf函數(shù)除了沒有返回值,就等同于setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
這個(gè)函數(shù)就是一個(gè)強(qiáng)制將緩沖區(qū)寫入磁盤的函數(shù),當(dāng)stream是null時(shí),將清洗所有緩沖區(qū),還有一個(gè)fpurge函數(shù),這里不提及。
打開流
FILE *fopen(const char *restrict filename, const char *restrict mode); FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream); FILE *fdopen(int fildes, const char *mode);從字面意義上就能看出這些函數(shù)的作用,fopen就是打開一個(gè)文件,freopen則是在一個(gè)指定的流上重新打開文件,一般用于將文件在一個(gè)預(yù)定義流上打開,fdopen則是將一個(gè)文件描述符打開,主要用于管道和網(wǎng)絡(luò)通信。
mode參數(shù)指定對(duì)IO流的讀寫方式,在學(xué)習(xí)C語(yǔ)言的時(shí)候可能就已經(jīng)有所接觸了
| r/rb | 讀打開 | O_RDONLY |
| w/wb | 寫打開 | O_WRONLY or O_CREAT or O_TRUNC |
| a/ab | 追加 | O_WRONLY or O_CREAT or O_APPEND |
| r+/r+b/rb+ | 讀寫打開 | O_RDWR |
| w+/w+b/wb+ | 讀寫打開 | O_RDWR or O_CREAT or O_TRUNC |
| a+/a+b/ab+ | 文件尾讀寫打開 | O_RDWR or O_CREAT or O_APPEND |
在系統(tǒng)手冊(cè)中也有一段關(guān)于mode的講解
The argument mode points to a string beginning with one of the following sequences (Additional characters may follow these sequences.):
``r'' Open text file for reading. The stream is positioned at the beginning of the file.
``r+'' Open for reading and writing. The stream is positioned at the beginning of the file.
``w'' Truncate to zero length or create text file for writing. The stream is positioned at the beginning of the file.
``w+'' Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.
``a'' Open for writing. The file is created if it does not exist. The stream is positioned at the end of the file. Subsequent writes to the file will always end up at the then current end of file, irrespective of any intervening fseek(3) or similar.
``a+'' Open for reading and writing. The file is created if it does not exist. The stream is positioned at the end of the file. Subsequent writes to the file will always end up at the then current end of file, irrespective of any intervening fseek(3) or similar.
The mode string can also include the letter b'' either as last character or as a character between the characters in any of the two-character strings described above. This is strictly for compatibility with ISO/IEC 9899:1990 (ISO C90'') and has no effect; the ``b'' is ignored.
Finally, as an extension to the standards (and thus may not be portable), mode string may end with the letter x'', which insists on creating a new file when used with w'' or ``a''. If path exists, then an error is returned (this is the equivalent of specifying O_EXCL with open(2)).
上面就多了一個(gè)x參數(shù),等價(jià)于open函數(shù)的O_EXCL參數(shù)。還有就是對(duì)于Unix緩解實(shí)際上二進(jìn)制和普通文件沒有任何區(qū)別,所以b參數(shù)將被忽視。
The fdopen() function associates a stream with the existing file descriptor, fildes. The mode of the stream must be compatible with the mode of the file descriptor. When the stream is closed via fclose(3), fildes is closed also.
原著中關(guān)于fdopen的講解過于繁瑣,實(shí)際上就是由于文件描述符已經(jīng)存在,流的模式必須兼容文件描述符,并且當(dāng)使用fclose關(guān)閉時(shí),文件描述符也被關(guān)閉。
Any created files will have mode "S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH" (0666), as modified by the process' umask value (see umask(2)).
還記得前面到的open和creat函數(shù)可以指定文件的權(quán)限,但是標(biāo)準(zhǔn)庫(kù)對(duì)于文件只有一種方式,就是以0666的模式創(chuàng)建文件,但是會(huì)被umask掩碼字刪減權(quán)限。
int fclose(FILE *stream);很簡(jiǎn)單,就是將緩沖區(qū)內(nèi)容寫入磁盤并關(guān)閉文件,如果緩沖區(qū)是自動(dòng)分配則會(huì)自動(dòng)回收緩沖區(qū)。
讀寫流
在學(xué)習(xí)C語(yǔ)言輸入輸出的時(shí)候,書上講的是scanf和printf格式化輸入輸出函數(shù),但是除了格式化輸入輸出以外,還有三種非格式化IO
一次讀寫一個(gè)字符
一次讀寫一行
直接IO,也叫作二進(jìn)制讀寫
The fgetc() function obtains the next input character (if present) from the stream pointed at by stream, or the next character pushed back on the stream via ungetc(3).
The getc() function acts essentially identically to fgetc(), but is a macro that expands in-line.
The getchar() function is equivalent to getc(stdin).
實(shí)際上還有三個(gè)讀取函數(shù),但是不在介紹范圍內(nèi)。上面已經(jīng)把三個(gè)函數(shù)都介紹了,fget就是獲得下一個(gè)輸入字符,getc函數(shù)等價(jià)于fgetc,但是可以被實(shí)現(xiàn)為宏定義用于內(nèi)聯(lián),getchar函數(shù)等同于getc(stdin),所以在實(shí)際開發(fā)中,應(yīng)當(dāng)注意fgetc和getc的區(qū)別。
If successful, these routines return the next requested object from the stream. Character values are returned as an unsigned char converted to an int. If the stream is at end-of-file or a read error occurs, the routines return EOF. The routines feof(3) and ferror(3) must be used to distinguish between end-of-file and error. If an error occurs, the global variable errno is set to indicate the error. The end-of-file condition is remembered, even on a termi-nal, and all subsequent attempts to read will return EOF until the condition is cleared with clearerr(3).
書上寫的挺繁瑣的,筆者就將手冊(cè)說明抄錄在上面,看不懂原著的解釋,看上面的解釋就懂了,
int ferror(FILE *stream); int feof(FILE *stream);void clearerr(FILE *stream);這兩個(gè)函數(shù)用于區(qū)分EOF和錯(cuò)誤發(fā)生,我們注意到,這里的參數(shù)是一個(gè)stream的文件指針,那我們是否可以猜測(cè)錯(cuò)誤碼和文件結(jié)束標(biāo)志是和文件結(jié)構(gòu)體相關(guān),筆者并沒有在文件結(jié)構(gòu)體中找到這兩個(gè)標(biāo)志,所以也只能當(dāng)做猜測(cè)。原著中則明確指出了大多數(shù)實(shí)現(xiàn)中存在這兩個(gè)標(biāo)志。最后一個(gè)函數(shù)則是用于清除這兩個(gè)標(biāo)志。
int ungetc(int c, FILE *stream);這個(gè)函數(shù)就是將已經(jīng)讀取的字符反壓回流。
int putc(int c, FILE *stream); int fputc(int c, FILE *stream); int putchar(int c);就如同前面的輸入函數(shù)一樣,這里就不在重復(fù)講述了。
一次讀取一行IO
char *fgets(char * restrict str, int size, FILE * restrict stream); char *gets(char *str);The fgets() function reads at most one less than the number of characters specified by size from the given stream and stores them in the string str. Read-ing stops when a newline character is found, at end-of-file or error. The newline, if any, is retained. If any characters are read and there is no error,a `\0' character is appended to end the string.
The gets() function is equivalent to fgets() with an infinite size and a stream of stdin, except that the newline character (if any) is not stored in the string. It is the caller's responsibility to ensure that the input line, if any, is sufficiently short to fit in the string.
fgets函數(shù)讀取不超過size參數(shù)規(guī)定的字符串從給定的流中,并將其存儲(chǔ)在str字符串中,讀取一直會(huì)持續(xù)到新行、EOF、錯(cuò)誤發(fā)生,并且null字節(jié)永遠(yuǎn)會(huì)在字符串末尾,這也就是說,讀取的字符串最大長(zhǎng)度是size - 1。
gets函數(shù)等價(jià)于一個(gè)指定了無限的size和標(biāo)準(zhǔn)輸入的fgets函數(shù),并且函數(shù)不會(huì)將換行符存儲(chǔ)在str參數(shù)中,但是調(diào)用者得自行保證輸入足夠短能存放在str參數(shù)中。由于可能會(huì)導(dǎo)致緩沖區(qū)溢出,所以實(shí)際上這個(gè)函數(shù)不被推薦使用。
puts函數(shù)不像gets函數(shù)一樣不安全,但是實(shí)際上也應(yīng)當(dāng)少用,因?yàn)樗鼤?huì)在一行輸出后,再次輸出一個(gè)換行符,而fgets和fputs則需要我們自己處理?yè)Q行符。
二進(jìn)制IO
size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);The function fread() reads nitems objects, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.
The function fwrite() writes nitems objects, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by ptr.
fread讀取nitems個(gè)對(duì)象,每個(gè)size字節(jié)長(zhǎng),從stream流中讀取,存儲(chǔ)在ptr位置,fwrite寫入nitems個(gè)對(duì)象,每個(gè)size字節(jié)長(zhǎng),寫到stream流中,從ptr位置讀取。兩句話就能說明這兩個(gè)函數(shù)的作用。
The functions fread() and fwrite() advance the file position indicator for the stream by the number of bytes read or written. They return the number of objects read or written. If an error occurs, or the end-of-file is reached, the return value is a short object count (or zero).
The function fread() does not distinguish between end-of-file and error; callers must use feof(3) and ferror(3) to determine which occurred. The function fwrite() returns a value less than nitems only if a write error has occurred.
返回值是讀寫的對(duì)象數(shù)目,如果到達(dá)了底部或者出錯(cuò),則返回實(shí)際寫入的對(duì)象數(shù)和0,需要feof和ferror來判斷區(qū)分。
定位流
和Unix系統(tǒng)提供的無緩沖IO一樣,標(biāo)準(zhǔn)C庫(kù)也提供了流定位函數(shù)
ftell和fseek函數(shù)。非常古老的函數(shù),最好少用
ftello和fseeko函數(shù)。只是把穩(wěn)健偏移量類型從long換成了off_t
fgetpos和fsetpos函數(shù)。被ISO C引入的,使用抽象文件位置記錄位置,跨平臺(tái)推薦使用
這些函數(shù)單位是都是字節(jié),其中whence和Unix系統(tǒng)的lseek函數(shù)是一樣的,rewind就是把流設(shè)置到頭位置。
off_t ftello(FILE *stream); int fseeko(FILE *stream, off_t offset, int whence);除了單位不同,和ftell、fseek沒有區(qū)別
int fgetpos(FILE *restrict stream, fpos_t *restrict pos); int fsetpos(FILE *stream, const fpos_t *pos);格式化IO
格式化IO函數(shù)可能是我們使用的最多最熟悉的,就5個(gè)函數(shù)
int printf(const char * restrict format, ...); int fprintf(FILE * restrict stream, const char * restrict format, ...); int dprintf(int fd, const char * restrict format, ...); int sprintf(char * restrict str, const char * restrict format, ...); int snprintf(char * restrict str, size_t size, const char * restrict format, ...);實(shí)際上還有其他輸出函數(shù),但是這里也不提及,printf就是向標(biāo)準(zhǔn)輸出寫,fprintf是向指定流寫,dprintf是向文件描述符寫,sprintf和snprintf都是是向一個(gè)字符串寫,但是snprintf加入了size參數(shù)確定大小,sprintf由于存在緩沖區(qū)溢出的隱患,所以也不建議使用了。
至于格式控制字符串如何書寫,原著中有,手冊(cè)中也非常詳細(xì),但是由于過長(zhǎng),所以不再摘錄出來。
下面是printf函數(shù)族的變體
這些函數(shù)被放在<stdarg.h>文件中,只是將可變參數(shù)表改成了va_list。
格式化輸入
int scanf(const char *restrict format, ...); int fscanf(FILE *restrict stream, const char *restrict format, ...); int sscanf(const char *restrict s, const char *restrict format, ...);與輸出相同,輸入函數(shù)也有對(duì)應(yīng)的變體
int vscanf(const char *restrict format, va_list arg); int vfscanf(FILE *restrict stream, const char *restrict format, va_list arg); int vsscanf(const char *restrict s, const char *restrict format, va_list arg);實(shí)現(xiàn)細(xì)節(jié)
實(shí)際上在Unix系統(tǒng)中,標(biāo)準(zhǔn)C庫(kù)最終都是會(huì)調(diào)用系統(tǒng)提供的接口,所以在FILE結(jié)構(gòu)體中,我們可以看到文件描述符的存在
int fileno(FILE *stream);雖然fileno函數(shù)是一個(gè)標(biāo)準(zhǔn)C庫(kù)函數(shù),但是卻是POSIX規(guī)定的。
在學(xué)習(xí)Unix系統(tǒng)開發(fā)的時(shí)候,多查系統(tǒng)手冊(cè),有了疑問多看看源代碼,是永遠(yuǎn)不會(huì)錯(cuò)的,而且有一些特殊的小技巧可以幫助我們開發(fā)找到錯(cuò)誤
就比如上面,讓C編譯器只進(jìn)行預(yù)處理,然后就能得到預(yù)處理后的文件,這樣看起來就更容易了,不需要我們?cè)诙鄠€(gè)頭文件中反復(fù)跳轉(zhuǎn)。
臨時(shí)文件
char *tmpnam(char *s); FILE *tmpfile(void);tmpnam函數(shù)產(chǎn)生一個(gè)有效路徑名字符串,如果s參數(shù)為null,則所產(chǎn)生的路徑存放在靜態(tài)區(qū),然后將指針返回,當(dāng)繼續(xù)調(diào)用時(shí),將會(huì)重寫整個(gè)靜態(tài)區(qū),如果ptr不是null,則將其存放在ptr中,ptr也作為函數(shù)值返回。
tmpfile創(chuàng)建一個(gè)臨時(shí)文件,并且在文件關(guān)閉時(shí)刪除文件,我們知道,進(jìn)程結(jié)束時(shí)會(huì)自動(dòng)關(guān)閉所有文件,所以當(dāng)進(jìn)程結(jié)束時(shí),也會(huì)刪除文件。
通常開發(fā)者是先調(diào)用tmpnam產(chǎn)生唯一路徑,然后使用該路徑創(chuàng)建文件,并立即unlink,前文說過,對(duì)一個(gè)打開的文件使用unlink等命令時(shí),不會(huì)立即刪除文件,而是等到最后文件關(guān)閉才刪除。
char *mkdtemp(char *template); int mkstemp(char *template);The mkstemp() function makes the same replacement to the template and creates the template file, mode 0600, returning a file descriptor opened for reading and writing. This avoids the race between testing for a file's existence and opening it for use.
The mkdtemp() function makes the same replacement to the template as in mktemp() and creates the template directory, mode 0700.
模板字符串是長(zhǎng)這樣的/tmp/temp.XXXXXX,最后六位是被替換掉的。還有,要注意不要使用常亮字符串作為template。
內(nèi)存流
在普通的流中,是和磁盤上的實(shí)際文件關(guān)聯(lián)在一起的,那么,是否存在一種虛擬的文件,將一塊內(nèi)存區(qū)域當(dāng)做文件來讀寫呢,實(shí)際上,是存在的,原著中提到了三個(gè)標(biāo)準(zhǔn)庫(kù)函數(shù)用于內(nèi)存流的創(chuàng)建,但是非常遺憾,這是glibc專屬的,沒有g(shù)libc的系統(tǒng)只能自己實(shí)現(xiàn),所以這里也不講述內(nèi)存流,如果有需要的朋友可以對(duì)照Linux下的手冊(cè)和原著學(xué)習(xí)。
標(biāo)準(zhǔn)IO的替代
在文章最前面也提到了,標(biāo)準(zhǔn)函數(shù)庫(kù)已經(jīng)有很久沒有做出修改了,而且從一路的學(xué)習(xí)下來,我們也看到了標(biāo)準(zhǔn)函數(shù)庫(kù)實(shí)際上存在著許多的缺陷。甚至很多東西在不同的系統(tǒng)上有著不同的表現(xiàn),我們甚至還無法確定這個(gè)標(biāo)準(zhǔn)的存在。所以現(xiàn)在也有許多的替代品被提出來方便開發(fā)者使用。但是要記得,不管庫(kù)怎么變化,實(shí)際上的系統(tǒng)調(diào)用還是那個(gè)。
總結(jié)
以上是生活随笔為你收集整理的[单刷APUE系列]第五章——标准I/O库的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android项目中刷新activity
- 下一篇: 计算机的前世