我在使用 dup2 系统调用将 STDOUT 重定向到文件时遇到了一个奇怪的问题。
我正在使用我在这里找到的两个函数: In C how do you redirect stdin/stdout/stderr to files when making an execvp() or similar call?
下面是我编写的一个简单程序,用于在出现错误后测试功能。 程序按预期工作并将输入写入文件。
int fd;
fpos_t pos;
int main(){
while(1){
char input[100];
printf("Please enter text: ");
gets(input);
printf("\nString = %s\n", input);
switchStdout("test.txt");
puts("THIS TEXT SHOULD REDIRECT\n");
printf("String(file) = %s\n", input);
revertStdout();
puts("This should come before the gets() ??\n");
}
return 0;
}
void switchStdout(const char *newStream)
{
fflush(stdout);
fgetpos(stdout, &pos);
fd = dup(fileno(stdout));
freopen(newStream, "w", stdout);
return;
}
void revertStdout()
{
fflush(stdout);
dup2(fd, fileno(stdout));
close(fd);
clearerr(stdout);
fsetpos(stdout, &pos);
}
调用 revertStdout() 函数后,程序似乎挂起。
我意识到,事实上,程序在打印“This should come before the gets() ??”之前已经调用了 gets()
输入文本后,程序会打印跳过的行。
这是终端输出,其中我以粗体输入内容:
Please enter text: Hello!!!!
String = Hello!!!!
Why am i able to type here ??
This should come before the gets() ??Please enter text:
String = Why am i able to type here ??
很抱歉这篇文章很长。程序按预期写入文件。
感谢任何人提供的任何帮助。
最佳答案
基本上,这就是当你在标准库背后偷偷摸摸时会发生的事情。
引用man setbuf
:
Normally all files are block buffered. When the first I/O operation occurs on a file,
malloc(3)
is called, and a buffer is obtained. If a stream refers to a terminal (asstdout
normally does) it is line buffered.
因此,您的 stdout
开始引用您的终端,并且是行缓冲的。然后你freopen
它来引用一个文件,因此(作为重新打开流的一部分),它变成了 block 缓冲。然后你dup2
fd,所以现在它再次引用终端,但它仍然是相同的流;标准库无法知道您已深入 stdout
的内部并更改了它所指的内容。因此它保持 block 缓冲,导致意外的行为。
在第一个输出之后更改流的缓冲会导致未定义的行为,尽管对于某些 C 库实现来说,如果缓冲区为空(因为在调用 fflush
之后就会出现这种情况),则可能会出现这种情况。您不应该指望这种行为。不过,您可以在 dup2
之后立即再次freopen
stdout
流,将 NULL 第一个参数传递给 freopen
,从而给标准库一个重新初始化的机会。
就其值(value)而言,switchStdout
中的 fflush
调用是不必要的,因为 freopen
有效地关闭了流。如果将 freopen
添加到 revertStdout
,它将重置错误和文件结束指示器,因此您可以删除对 clearerr
的调用.
关于c - 使用 dup2 系统调用重定向输出的奇怪问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43194259/