【问题标题】:Strange issue redirecting output using dup2 sys call使用 dup2 系统调用重定向输出的奇怪问题
【发布时间】:2017-04-03 21:05:51
【问题描述】:

我在使用 dup2 系统调用将 STDOUT 重定向到文件时遇到了一个奇怪的问题。

我正在使用在这里找到的 2 个函数: 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()

在我输入文本后,程序会打印跳过的行。

这里是终端输出,我用粗体输入:

请输入文字:Hello!!!!

String = 你好!!!!

为什么我可以在这里打字??
这应该出现在 gets() 之前??

请输入文字:

String = 为什么我可以在这里输入??

抱歉,帖子太长了。程序按预期写入文件。

感谢任何人提供的任何帮助。

【问题讨论】:

  • 如果您想重新打开流以使用不同的描述符或句柄,您可能需要fdopen()。它不在标准库中,但 Unix、Windows 和 OSX 都支持。

标签: c unix redirect


【解决方案1】:

基本上,当您在标准库的背后偷偷摸摸时会发生这种情况。

引用man setbuf:

通常所有文件都是块缓冲的。当对文件进行第一次 I/O 操作时,会调用malloc(3),并获得一个缓冲区。如果一个流引用一个终端(就像stdout 通常那样),它是行缓冲的。

所以,您的 stdout 开始引用您的终端,并且是行缓冲的。然后你 freopen 它来引用一个文件,所以(作为重新打开流的一部分),它变成了块缓冲。然后你dup2 fd,所以现在它又指的是终端,但它仍然是同一个流;标准库不知道您已经深入到stdout 的内部并更改了它所指的内容。所以它保持块缓冲,导致意外行为。

在第一次输出后更改流的缓冲会导致未定义的行为,尽管在某些 C 库实现中,如果缓冲区为空是可能的(因为它会在调用 fflush 之后出现)。你不应该指望这种行为。但是,您可以在 dup2 之后立即再次 freopen stdout 流,将 NULL 第一个参数传递给 freopen,从而使标准库有机会重新初始化。

不管怎样,switchStdout 中的fflush 调用是不必要的,因为freopen 有效地关闭了流。如果您将freopen 添加到revertStdout,它将重置错误和文件结束指示符,因此您可以删除对clearerr 的调用。

【讨论】:

  • 在 dup2 修复后添加 freopen(NULL, "w", stdout)。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-12-17
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 2015-12-13
  • 1970-01-01
  • 2015-01-18
相关资源
最近更新 更多