fputc vs putc in C

问题描述 投票:17回答:1

我正在阅读Kernighan的C编程书,偶然发现putcfputc,想知道两者之间有什么区别,或者何时使用另一种。我在StackOverflow上找到了一些有关该主题的帖子,但在理解它们时遇到了一些麻烦。

正如他们在这里提到的[putc needs stdout, vs puts):

  1. 根据Kernighan的书putc等效于fputc,但是putc可以实现为宏,并且putc可以多次评估其流参数。

  2. putcfputc之间的区别在于,使用putc可能会运行本质上不安全的宏版本,因为它可能不得不多次评估其流参数。这会导致大多数人不知道的并发症,因此不会引起注意,因此fputc更好用。 fputc的宏没有此问题。

问题:

  1. [putc可以实现为宏,但是用fputc做同样的问题是什么?

  2. 第二句话提到了一些复杂性和安全性问题。那是什么?

  3. putc多次评估其自变量。因此,与评估参数相比,它有什么优点或缺点。

c stdio
1个回答
18
投票

宏实现的问题是,如果任何参数有副作用,这些副作用可能会被多次评估,可能会导致未定义的行为。考虑这个玩具示例:

#define SQUARE(x) ((x) * (x))

在大多数情况下,这将按预期运行,但是如果您传递诸如f()的表达式,则调用函数f()的副作用会发生[[两次,而不是一次] >,因为预处理器只是一个文本转换器,而忽略了C:int f() { printf("f() was called\n"); return 42; } ... int x = SQUARE(f()); // This calls f() twice! It gets expanded to this: // int x = (f() * f());

为了正确理解,如果将putc函数实现为宏,则可能会多次评估其stream参数。因此,如果该流来自某个函数:

FILE *get_file() { // Potential side effects could happen here return some_file; } ... putc('A', get_file());

然后可能会导致函数get_file()被多次调用,并可能产生有害的副作用。

当然,解决方案是只调用fputc()之类的常规函数​​,而不是putc()。由于它不是宏,因此多次评估其参数没有任何潜在的问题。宏有时可能很危险,因此请谨慎使用。

© www.soinside.com 2019 - 2024. All rights reserved.