許多初學者以為fgetc、fputc中的f代表file,專門用於文件操作;而getc、putc用於標準輸入輸出。但查看函數聲明會發現:四個函數都接受FILE*參數,都能操作文件流。真相是什麼?
這一區別源自《UNIX環境高級編程》(APUE)的說明:f代表function,而非file。
宏直接文本替換,參數若含副作用會導致多次求值:
#define MAX(a,b) ((a) > (b) ? (a) : (b)) int x = 5, y = 3; int z = MAX(x++, y++); // 展開後:((x++) > (y++) ? (x++) : (y++)) // x或y會被遞增兩次!
規則:getc/putc的參數不能包含副作用表達式(如getc(fp++)),而fgetc無此限制。
函數有地址,可作為函數指針參數傳遞;宏無地址:
int (*func_ptr)(FILE*) = fgetc; // 合法 // int (*func_ptr)(FILE*) = getc; // 非法:宏不是函數
這在需要回調函數的場景(如qsort比較函數)至關重要。
因此getc通常比fgetc快一點。但現代編譯器優化(內聯、LTO)常能消除這一差距。APUE用「很可能」措辭正是此意。
在glibc中,getc和fgetc實際上都是函數!stdio.h中:
#define getc(_fp) _IO_getc(_fp) // 宏包裝函數調用
_IO_getc在libio.h中聲明為函數。這意味著:
getc/putc,性能略優且代碼簡潔fgetc/fputcfgetc/fputcfgetc/fputc,避免宏實現差異f前綴真正含義是function,區別在於函數vs宏的實現機制。理解這一點,能避免副作用Bug、正確使用函數指針、做出性能優化選擇。在現代編譯器和glibc下,實際差異已很小,但語義區別依然重要。