c - 使用 dup2 系统调用重定向输出的奇怪问题

标签 c unix redirect

我在使用 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 (as stdout 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/

相关文章:

c - 多个源的 makefile

linux - 如果使用 AND 条件,awk -F 找不到字符串

Django 测试 - 检查重定向 View 的消息

c# - Url.IsLocalUrl 产生具有相同值的不同结果?

php - .htaccess:多个 .htaccess 文件如何工作?

c - 为什么我们包含 stdlib.h?

c++ - C 中的链表和 getifaddrs()

c libcurl CURLOPT_POSTFIELDS 奇怪的错误

linux - 编译时指定库目录

bash - 带有 wget 的 Shell 脚本获取减去 1 天的日期