C 当写入以换行结束时,行缓冲文件和非缓冲文件之间是否存在差异?

C 当写入以换行结束时,行缓冲文件和非缓冲文件之间是否存在差异?,c,flush,buffering,C,Flush,Buffering,我就在那里,几乎要(再一次)给一个分包商发一封愤怒的邮件。他们使用printf(…)来报告错误,而不是fprintf(stderr,…),我认为这是愚蠢的,因为stdout是(行)缓冲的。特别是当我在断言处理程序中发现一个打印时(可能以abort结尾,它不会刷新打开的文件) 然而,仔细看这些照片,它们都以一条新线结束。由于stdout是行缓冲的(默认情况下),它让我想到:在刷新方面有什么区别吗?事实上,如果一个流是行缓冲的,并且它的所有输出都以换行结束,那么为了确保输出不会延迟,并且在异常终止时

我就在那里,几乎要(再一次)给一个分包商发一封愤怒的邮件。他们使用
printf(…)
来报告错误,而不是
fprintf(stderr,…)
,我认为这是愚蠢的,因为
stdout
是(行)缓冲的。特别是当我在断言处理程序中发现一个打印时(可能以
abort
结尾,它不会刷新打开的文件)


然而,仔细看这些照片,它们都以一条新线结束。由于stdout是行缓冲的(默认情况下),它让我想到:在刷新方面有什么区别吗?

事实上,如果一个流是行缓冲的,并且它的所有输出都以换行结束,那么为了确保输出不会延迟,并且在异常终止时不会丢失输出,行缓冲和无缓冲一样好。(如果在需要时始终手动使用
fflush
,则可以做出类似的声明。)

但是,您所做的声明以及您所依赖的“
stdout
是行缓冲的(默认情况下)”,是错误的。相反,除了
stderr
,默认情况下,所有stdio文件只有在连接到交互式设备(tty)时才进行行缓冲(或可能无缓冲)。否则,它们将被完全缓冲

根据7.21.3文件第7部分(重点):

在程序启动时,三个文本流是预定义的,不需要显式打开——标准输入(用于读取常规输入)、标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。初始打开时,标准错误流没有完全缓冲;当且仅当可以确定流不引用交互设备时,标准输入流和标准输出流被完全缓冲

和7.21.5.3
fopen
功能,^8:

打开时,流被完全缓冲,当且仅当可以确定它不引用交互设备时。流的错误和文件结束指示符被清除

当写入以换行结束时,行缓冲文件和非缓冲文件之间是否存在差异

在同花顺方面有什么区别吗

给定刷新是“将任何未写入的缓冲区内容传输到主机环境”C11dr§7.21.3 4

如果所有
stdout
输出以
'\n'
结束,且该流未缓冲或行缓冲,则不希望后续刷新执行任何操作,因为没有未写入的数据


这里的C规范有点松散。具体行为由实现定义。最好使用
fflush(stdout)以确保此时刷新输出

错误消息应该在标准错误中报告,这样它们就不会在管道中消失,并混淆以下程序。因此,与刷新问题无关,在标准输出上报告错误是错误的。只有当输出发送到终端时,才使用\n。你不喜欢的。如果它被重定向,则没有区别。isatty()决定发生什么。Andreas:“stdout是行缓冲的(默认)”-->我没有发现C指定了这个。当然,这是实现定义的行为。有趣的断言“所有stdio文件…”。对此有任何支持/引用吗?@chux:引证已添加。不清楚“默认缓存行”是如何出现的,因为流是无缓冲、完全缓冲或缓存行的。交互设备条件设置为完全缓冲,保留未缓冲或行缓冲。也许有更多的东西可以确保
stdout
作为行缓冲?我也不确定有多少实现真正遵循这一点——在Linux上,如果stdout(直接)引用网络套接字,即使该网络套接字远程连接到交互设备,它也将被完全缓冲。如果它连接到pty(伪终端),即使pty未连接到交互设备,它也将被线路缓冲。我想标准从来没有定义什么是“交互设备”,因此留下了很多回旋余地。@chrisdd:socket不是交互设备。该标准对其实现进行了定义,但对于POSIX和实际应用而言,“交互式设备”意味着tty。关于“可以确定”,一个实现可能会决定它永远不能确定,然后默认情况下总是使用无缓冲或行缓冲模式,但假设一个实现这样做是不安全的,而一个实现这样做会有糟糕的性能特征,例如在循环中执行
putc('\n',f)
。最好使用fflush(stdout);以确保在该时间之前刷新输出。我的意思是,如果您发出错误消息,请将其发送到stderr
,然后刷新它。@AndrewHenle同意。即使在出现错误的情况下,
stderr
,先前的
fflush(stdout)
也有助于确保输出顺序与混合输出。然而,当它的时间为错误消息,有时最好避免无关的其他积极。