【问题标题】:Is getc a macro or a function?getc 是宏还是函数?
【发布时间】:2015-09-23 14:32:13
【问题描述】:

我试图找出getc 和fgetc 之间的区别。当时看到这样的说法:

getc 和 fgetc 的区别在于 getc 可以实现为宏,而 fgetc 不能实现为宏。

那么,getc 真的是一个函数还是一个宏?如果是宏,它会调用其他函数。那么,getc 是否在 C 中实现?

【问题讨论】:

  • 这取决于你的 C 库,真的。 getc() 可能被实现为宏......或者它可能不会,这可能会在未来发生变化。
  • 所以,它不是像fgetc、fgets那样的独特功能。是写的吗?

标签: c linux unix macros


【解决方案1】:

getc 和 fgetc 的区别在于 getc 可以实现为宏,而 fgetc 不能实现为宏。

这是不正确的。

除了少数例外,任何 C 标准库函数可以另外实现为宏,但该宏的编写方式有一些限制(因此宏仍可用作如果它是一个函数)。

引用N1570 第 7.1.4 节:

在头文件中声明的任何函数都可以另外实现为 头文件中定义的类似函数的宏,[...] 任何调用 作为宏实现的库函数应扩展为代码 它只对每个参数进行一次评估,完全受保护 必要时使用括号,因此通常可以安全地使用任意 表达式作为参数。

getc 的特别之处在于其中一项限制可以放宽 (7.21.7.5):

getc 函数等价于 fgetc,除了如果 它被实现为一个宏,它可以评估 stream 超过 一次,所以参数永远不应该是一个有副作用的表达式。

fgetc 和 getc 的声明是:

int fgetc(FILE *stream);
int getc(FILE *stream);

stream 参数(例如,在像 fgetc(stdin) 或 getc(file) 这样的调用中几乎总是一个没有副作用的表达式,但规则仍然禁止将 fgetc 定义为计算其参数超过一次,以防万一程序员写了fgetc(file_list[i++])之类的东西。对于getc,该规则放宽了,因此可以将其定义为宏(在某些情况下可以显着提高效率),同时可能会破坏@987654335之类的东西@。

在fgetc 的情况下,将其实现为宏而不是仅仅作为函数可能不会有太多优势。关键是标准明确允许这样做。

那么,getc 是否在 C 中实现?

也许吧。 任何 C 库函数都不需要在 C 中实现。某些函数可能在汇编程序或任何其他语言中实现 - 或者它们可能是编译器内在函数。通常大多数或所有 C 标准库函数都是用 C 实现的,但标准只指定它们的工作方式,而不是它们的编写方式。

【讨论】:

    【解决方案2】:

    getc 是 C99 标准第 7.21.7.5 节中所述的函数,可能会或可能不会作为宏实现:

    getc 函数等价于fgetc,只是如果它被实现为宏,它可能会多次计算stream,因此参数绝不应该是具有副作用的表达式。

    它不适用于具有副作用的参数。例如——

    int c = getc(*fpp++);
    

    【讨论】:

    • 所以,这取决于 C 的版本
    • @mohan:不,它不依赖于C的版本。标准对fgetc和getc的描述在C90、C99和C11中基本相同。
    • @mohan 不,它不会依赖于 C 的版本。
    • fgetc,可以实现为宏。关于如何编写该宏有更多限制。详情见我的回答。
    • @ameyCU:任何标准 C 库函数都可以实现为宏。在fgetc 的情况下可能没有太多理由这样做,但这是允许的。看我的回答。
    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 2012-09-28
    • 2017-02-09
    相关资源
    最近更新 更多