看书的时候,发现了这四个函数,想知道他们的不同。结果上网查发现很多人说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)这个函数的声明又是这样的:
所以,最后,各位亲们,我想说的是,不要再纠结了,这两个函数敞开了用吧,区别不是很大,一般不会出啥问题的!