getc() 和 fgetc() - 主要区别是什么?

57

我到处都看到“它几乎是相同的”,或者类似的话...

GNU C编程教程中:

GNU C库中还有另一个函数叫做fgetc。它在大多数方面与getc相同,除了getc通常被实现为宏函数并且高度优化,因此在大多数情况下更可取。(在从标准输入读取时,因为人类键入较慢,所以getc与fgetc的速度大致相同,但在从非交互式由人类生成的流中读取时,fgetc可能更好。)

它们之间的其他区别是什么?我听说它们各自有不同的实现(而且一个可以用作宏),但是,它们之间有什么使它们足够不同,以便它们都在标准C库(或规范)中?


2
这里有很好的信息:https://dev59.com/X2435IYBdhLWcg3w1jyV - dcaswell
4
@user814064,你提供的链接涉及到fgetsfgetc的比较,而原帖讨论的是 getcfgetc 的区别。请问需要翻译什么其他内容吗? - David Ranieri
在那个链接中提到了getc(),以及它的优点。 - dcaswell
2
@user814064,您可以直接链接到答案(点击 分享)https://dev59.com/X2435IYBdhLWcg3w1jyV#5186605 - David Ranieri
非常感谢。我发帖还不到一周,还有很多要学习的。我以为那是Facebook或者什么的。 - dcaswell
3个回答

58

来自《Unix环境高级编程》:

...

getcfgetc 的区别在于 getc 可以被实现为宏,而 fgetc 不能被实现为宏。这意味着三件事:

  • getc 的参数不应该是带有副作用的表达式。
  • 由于 fgetc 被保证为一个函数,我们可以取得它的地址。这使我们能够将 fgetc 的地址作为参数传递给另一个函数。
  • 调用 fgetc 可能比调用 getc 花费更长时间,因为调用函数通常需要更多的时间。

...


我加了+1,但是:为什么标准库中两者都有?为什么不能都是宏? - Joe DF
@day,你是指“how”作为“具体的实现细节是什么”还是“在道德或技术上你怎么做到的”? - Peter - Reinstate Monica
1
@JoeDF - 为什么两者都要?最基本的原因是向后兼容。原始的标准I/O包含了两个函数 - C标准采用了这两个函数以实现向后兼容(避免破坏现有的、可工作的代码)。请注意,如果您使用#undef getc,库中必须存在一个函数,即使它通常是一个宏。此外,现在有了多线程和锁等技术,宏实现的性能优势更具争议性(但这取决于所需的锁如何实现)。 - Jonathan Leffler

23

看起来区别在99.9%的情况下是没有意义的。

一个可能会有所不同的要点是 - 手册页面中说getc()可能被实现为一个宏,该宏对流进行多次求值

这可能会导致一些(不是很有用的)情况下出现奇怪的行为,例如:

FILE *my_files[10] = {...}, *f=&my_files[0];
for (i=0; i<10; i++) {
    int c = getc(f++);    // Parameter to getc has side effects!
}

如果getc评估f++超过一次,它将在每次迭代中使f前进多次。相比之下,在这种情况下fgetc是安全的。


3
基本上它们是相同的(或者足够相似,不需要过多担心)。你应该看看它们的实现:GNU libcMUSL libc 都是自由软件实现。并且现在它们可以作为内联函数实现(与宏一样快)。
但我不会过多地担心。在现实生活中,I/O 主要受硬件限制(例如访问磁盘的时间)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接