【问题标题】:C: printf still not flushing before while loop, even with new line character in format string [duplicate]C:在while循环之前printf仍然没有刷新,即使格式字符串中有换行符[重复]
【发布时间】:2020-04-07 20:18:37
【问题描述】:

我读过很多人问为什么 printf 在 while 循环之前不起作用;答案是它没有刷新标准输出,因为它们的格式字符串中没有换行符。但是,以下简单代码仍然没有为我产生输出:

#include <stdio.h>

int main() {

    printf("Hello world!\n");
    while (1);

    return 0;

}

但是,在 printf 调用之后添加 fflush(stdout); 会产生输出。换行符应该是不必要的,那为什么没有它就行不通呢?

【问题讨论】:

  • 我不复制。你的系统是什么?你如何调用你的程序?
  • @user3121023 @AProgrammer 我在 Windows 上使用 mingw 和 Eclipse。但是,如果我省略了 while 循环,那么在没有 fflush(stdout); 的情况下输出会非常好。
  • 为什么你认为换行符让它变得不必要了?有很多因素。在某些常见情况下,以换行符结束字符串会导致标准库函数刷新流。正如您所发现的,并非总是如此。所以不要依赖隐含的行为。如果要刷新流,请刷新它。
  • 您的运行时没有将 Eclipse 的输出视为交互式设备,因此会进行完全缓冲。我对 Windows 和 Eclipse 的了解不够多,无法进一步评论,但 IMO 这是您的代码以外的其他地方的错误。
  • "换行符应该是不必要的," --> 不正确的结论。取决于缓冲模式。见What are the rules of automatic stdout buffer flushing in C?

标签: c printf


【解决方案1】:

stdout 在连接到终端时是行缓冲的(在换行时刷新),而在其他情况下是块缓冲(在缓冲区已满时刷新)是很常见的。

例如,

#include <stdio.h>
#include <unistd.h>

int main(void) {
   printf("foo\n");
   sleep(5);
   return 0;
}

测试:

$ ./a
foo
[5s pause]

$ ./a | cat
[5s pause]
foo

(Linux 上的 gcc)


我在 Windows 上使用 mingw 和 Eclipse。

似乎 Eclipse 正在将程序的标准输出连接到管道,以便它可以收集输出并将其显示在其窗口中。因此,您的程序将块缓冲用于标准输出。

【讨论】:

  • "Eclipse 正在将程序的标准输出连接到管道" 我本来希望使用等效的伪终端。 Eclipse 不这样做有什么原因吗?
  • @AProgrammer,为了清楚起见,我不是根据经验说话;我只是根据OP的观察来进行。也就是说,我不知道,但如果 Windows 没有与 pttys 等效的功能,我不会感到惊讶。事实上,如果它确实有一个相当于 pttys 的东西,我真的会感到惊讶。但我对这些事情并不完全了解。这也可能是为了避免可移植性问题,特别是因为 Eclipse 是用 Java 编写的。
【解决方案2】:

@schot here 的回答非常好。 他说:

C99 标准没有指定这三个标准流是无缓冲的还是行缓冲的:这取决于实现。我知道的所有 UNIX 实现都有一个行缓冲标准输入。在 Linux 上,stdout 是行缓冲的,stderr 是非缓冲的。

确保您的行将被直接打印的一种方法是使 stdout 无缓冲:

setbuf(stdout, NULL);
/* or */
setvbuf(stdout, NULL, _IONBF, 0);

但是您只能执行一次,并且必须在您写入标准输出或对其执行任何其他操作之前执行此操作。 (C99 7.19.5.5 2)

附加信息:

换行符不应该刷新输出吗?

-这取决于,如果输出设备被确定为 interactivee(例如终端),则换行符刷新缓冲区。否则新行不会刷新缓冲区。

什么构成交互式设备是实现定义的(C99 第 5.1.2.3/6 节)

【讨论】:

  • 但是不管stdout是无缓冲的还是行缓冲的,换行符不应该刷新输出吗?
  • @TheGreenFrog 正如答案中的报价所说“这取决于实施”。也就是说,不需要在换行符之后刷新,显然 mingw 实现不需要。
  • @TheGreenFrog 这取决于,如果输出设备被确定为交互式(如终端),那么换行符会刷新缓冲区。 (构成交互式设备的内容是实现定义的)。否则新行不会刷新缓冲区(我们说标准输出是“完全缓冲的”)
猜你喜欢
  • 2014-04-18
  • 1970-01-01
  • 2017-01-20
  • 1970-01-01
  • 2018-10-23
  • 2017-07-09
  • 2010-12-15
相关资源
最近更新 更多