我试图findgetc
和fgetc
之间的区别。 那时候我看到一个声明就是:
getc和fgetc的区别在于getc可以被实现为一个macros,而fgetc不能被实现为一个macros。
那么, getc
真的是一个函数,还是一个macros? 如果是macros,则调用其他函数。 那么, getc
是用C实现还是不行?
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
是放松的,所以它可以被定义为一个宏(在某些情况下可以更有效),同时可能会破坏getc(file_list[i++])
。
在fgetc
的情况下,将其作为一个宏而不是仅仅作为一个函数来执行它可能没有多大的优势。 关键是标准明确允许它。
那么,
getc
是用C实现还是不行?
也许。 在C语言中没有要求实现任何 C库函数。一些函数可以用汇编语言或其他语言来实现 – 或者它们可能是编译器内在函数。 通常,大多数或所有的C标准库函数都是用C实现的,但是标准只是指定了它们是如何工作的,而不是如何编写的。
getc
是C99 standard section 7.21.7.5
所述的一个函数,可能会或可能不会被实现为macro
。
7.21.7.5 –
2 getc函数相当于fgetc,但是如果它是作为一个宏实现的,它可以多次计算流,所以参数不应该是带有副作用的表达式。
它不能正确使用具有副作用的参数(流参数)值。例如 –
int c=getc(*f++);