看書的時候,發現了這四個函數,想知道他們的不同。結果上網查發現很多人說fgetc、fputc的f代表的是file,就是這兩個函數是和文件有關的!但是一看他們的函數聲明,如下圖:
發現他們的參數裡面都有文件指針啊!後來又去翻了翻APUE,發現那個f代表的其實是function,這是怎麼一回事呢,且聽我慢慢道來!
fgetc和getc他們的區別並不是在他們的使用上,而是在他們的實現上!具體來說,就是帶f的(fgetc、fputc)實現的時候是通過函數來實現的,而不帶f(putc、getc)的,實現的時候是通過宏定義來實現的!關於他們的不同點,就拿getc和fgetc來說,APUE(p115)上是這麼寫的:
<1>.getc的參數不應當是具有副作用的表達式。
<2>.因為fgetc一定是一個函數,所以可以得到其地址。這就允許將fgetc的地址作為一個參數傳送給另一個函數。
<3>.調用fgetc所需時間很可能長於調用getc,因為調用函數通常所需的時間長於調用宏。
首先說第一點應該怎麼理解呢,這個是因為宏這個東西坑蠻多,這裡舉個經典的例子。
在這個程序中,z2我想算8*8,但是傳入的參數是5+3,6+2,宏替換之後就變成了5+3*6+2,最後結果就成了25。
那麼第二點又是什麼意思呢,這個其實就是一個函數指針,一個函數的地址能夠傳遞給一個函數指針,讓其來調用,但是宏就不行了!比如說下面這段代碼:
由於MAX是個宏,所以就不能賦值給函數指針了!
關於第三點,這就涉及到一點匯編的知識了,在匯編語言中,函數的調用是通過棧來實現的!就是調用的時候壓棧,調用完了再彈棧(關於匯編我也不是很清楚,所以敘述的有點粗糙,還望見諒!),比如下面這段代碼:
1 #include<stdio.h> 2 void func3() 3 { 4 printf("Hello,World!"); 5 } 6 void func2() 7 { 8 func3(); 9 } 10 void func1() 11 { 12 func2(); 13 } 14 int main(int argc,char *argv[]) 15 { 16 func1(); 17 return 0; 18 }
我用gdb調試,在第4行設置了一個斷點,查看它的函數調用棧如下:
而通過宏調用是不用壓棧的,所以getc的速度就比fgetc快那麼一點。
不過,關於這個是有一點例外,就是有時候調用函數並不是通過棧來實現的,所以作者用了一個很可能的詞匯。關於這個問題,這個帖子講的非常好(fgetc和getc,哪個速度快?)。
OK,上面就是fgetc和getc的不同了!不過需要補充一點的是關於GNU C下這兩個函數其實是一樣的,他們都是通過函數來實現的,然後getc再簡單粗暴地增加了一個宏的聲明。具體如下:
在stdio.h這個文件中getc的聲明是這樣的:
而在libio.h裡面那個_IO_getc (_fp)這個函數的聲明又是這樣的:
所以,最後,各位親們,我想說的是,不要再糾結了,這兩個函數敞開了用吧,區別不是很大,一般不會出啥問題的!