fputc vs putc in C

时间:2012-12-23 05:41:34

标签: c stdio

我正在阅读Kernighan撰写的C编程书,并且遇到了这个问题。两者之间的差异或他们各自的使用标准。我在StackOverflow上发现了一些处理此问题的帖子。我得到了答案的一部分,但理解它们有点麻烦。

正如他们在此提到的那样(putc needs stdout, vs puts):

  
      
  1. 根据Kernighan的书putc相当于fputc,但putc可以实现为宏,putc可以多次评估其流参数。

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

  4.   

问题:

  1. putc可以作为宏实现,但与fputc相同的问题是什么?

  2. 第二个陈述提到了一些并发症和安全问题。那些是什么?

  3. putc不止一次地评估其参数。那么与评估论证相比,它有什么优势或劣势。

1 个答案:

答案 0 :(得分:17)

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

#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()。由于它不是一个宏,因此不会有多次评估其参数的任何潜在问题。宏有时会很危险,所以要小心使用它们。