未结束EOL的重定向STDOUT停留在缓冲区中,并且未显示



我正在编写一个程序(命令行前端(,它重定向任意命令行程序的stdout和stdin。问题是独立于平台的。为了理解这个问题,我编写了一个简单的命令行程序来解决这个问题:

#include <stdio.h>
main () {
char Expression[200];
printf ("Enter first expression: "); scanf ("%s", Expression);
printf ("You have entered: %sn", Expression);
printf ("n");
printf ("(Now query with Stderr)n");
fprintf (stderr, "Enter second expression: "); scanf ("%s", Expression);
printf ("You have entered: %sn", Expression);
}

stdout"输入第一个表达式"位于输出缓冲区中,不会通过重定向的stdout管道发送到我的程序。因此,第一个问题是"输入第二个表达式",因为缓冲区问题只发生在stdout中,而不发生在stderr中。如果用户键入了输入并按下RETURN,则发送缓冲区内容(第一个查询(。所以stdout只在EOL之后通过管道运行,stderr会立即显示输出。

如果您运行Info-Zip UNZIP,并且您正在解压缩已经存在的文件,UNZIP将发送一个查询:

replace myfile.txt? [y]es, [n]o, [A]ll, [N]one, [r]ename:

并且此查询是通过stderr发送的,因此不会出现问题。但其他程序也遇到了这个问题。

Windows 10的命令行前端已被重写。如果出现这种情况(例如,在覆盖现有文件时使用cmd.exe集成的"复制"命令(,新的命令行前端将等待3秒(!(,然后显示缓冲的查询。因此,微软程序员似乎需要编写一个"肮脏的黑客"来解决这个问题。

我的问题是:如果没有收到EOL,如何强制用户程序吐出stdout缓冲区?我可以完全访问用户程序由同一会话中的一个特殊帮助程序运行的会话,该程序可以在我的图形前端程序和运行cmd.exe的文本窗口之间进行通信。

我现在意识到"fflush"命令必须放在用户程序中。重定向时总是缓冲Stdout,而不是Stderr。这就是stderr输出可能发生在stdout输出之前的原因。我编写了一个测试示例,其中stderr输出在显示之前显示了4行。

因此,这意味着所有编写stdout和stderr或编写用户查询的程序员都必须刷新stdout:

//first case: query and user input
char Expression[200];
printf ("Enter an expression: "); fflush (stdout); scanf ("%s", Expression);
printf ("You have entered: %sn", Expression);
//second case: stderr output
fflush (stdout); fprintf (stderr, "An error has occured.");

我查看了互联网上的帖子,似乎所有平台都会出现这个问题。

因此,如果您使用stdout和stderr编写程序,请在这两种情况下使用fflush(stdout(。相反的情况(使用stderr,然后使用stdout(没有问题,因为stderr不会得到缓冲。(我希望我对所有平台都是正确的。(

不,我没有覆盖用户在命令行前端程序中执行的程序的选项。

每个人都可以将stdout和stderr重定向到单个文本文件:

[C:] userprog >output.txt 2>&1 

这意味着stdout和stderr都被重定向到一个文件"output.txt"。如果stdout没有正确刷新,文本文件中会显示不正确的顺序。

我已经意识到,在这些情况下,所有来自专业来源的程序都会刷新stdout并生成正确的顺序。

最新更新