【问题标题】:Is printf equivalent to dprintf(STDOUT_FILENO)?printf 是否等同于 dprintf(STDOUT_FILENO)?
【发布时间】:2022-01-06 02:49:19
【问题描述】:

我正在学习一些关于 Linux 中的 PIPE 的知识,但我遇到了一些我无法弄清楚的东西。我正在阅读 rozmichelle 的博客 http://www.rozmichelle.com/pipes-forks-dups/#pipelines。下面的代码是对父进程通过PIPE传递给子进程的三个词进行排序。

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  int fds[2];                      // an array that will hold two file descriptors
  pipe(fds);                       // populates fds with two file descriptors
  pid_t pid = fork();              // create child process that is a clone of the parent
  
  if (pid == 0) {                  // if pid == 0, then this is the child process
    dup2(fds[0], STDIN_FILENO);    // fds[0] (the read end of pipe) donates its data to file descriptor 0
    close(fds[0]);                 // file descriptor no longer needed in child since stdin is a copy
    close(fds[1]);                 // file descriptor unused in child
    char *argv[] = {(char *)"sort", NULL};   // create argument vector
    if (execvp(argv[0], argv) < 0) exit(0);  // run sort command (exit if something went wrong)
  } 

  // if we reach here, we are in parent process
  close(fds[0]);                 // file descriptor unused in parent
  const char *words[] = {"pear", "peach", "apple"};
  // write input to the writable file descriptor so it can be read in from child:
  size_t numwords = sizeof(words)/sizeof(words[0]);
  for (size_t i = 0; i < numwords; i++) {
    dprintf(fds[1], "%s\n", words[i]); 
  }

  // send EOF so child can continue (child blocks until all input has been processed):
  close(fds[1]); 

  int status;
  pid_t wpid = waitpid(pid, &status, 0); // wait for child to finish before exiting
  return wpid == pid && WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}

在上面的代码中,父进程使用dprintf,但是我想知道我们是否可以将父进程的标准重定向到PIPE的输入。所以我尝试编写下面的代码。

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  int fds[2];                      
  pipe(fds);                      
  pid_t pid = fork();              
  
  if (pid == 0) {                  
    dup2(fds[0], STDIN_FILENO);    
    close(fds[0]);                 
    close(fds[1]);                 
    char *argv[] = {(char *)"sort", NULL};   
    if (execvp(argv[0], argv) < 0) exit(0);  
  } 

  // if we reach here, we are in parent process
  close(fds[0]);                 
  const char *words[] = {"pear", "peach", "apple"};
  // write input to the writable file descriptor so it can be read in from child:
  size_t numwords = sizeof(words)/sizeof(words[0]);
  dup2(fds[1],STDOUT_FILENO);//redirect stdout
  close(fds[1]); //fds[1] is not used anymore
  for (size_t i = 0; i < numwords; i++) {
    printf("%s\n", words[i]); 
  }
  close(STDOUT_FILENO);
  int status;
  pid_t wpid = waitpid(pid, &status, 0); 
  return wpid == pid && WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}

重定向后,我使用了printf,在我的理解中会输出到STDOUT。但是,这段代码什么也没打印,而第一个代码打印如下:

apple
peach
pear

我不明白为什么会这样,是不是我理解有误?

【问题讨论】:

  • 在 printfs 循环后添加fflush(stdout);
  • @Shawn,谢谢!太棒了!
  • 我会使用fclose(stdout); 而不是close(STDOUT_FILENO); 来获得自动冲洗。
  • @TedLyngmo,好点子!

标签: c linux printf


【解决方案1】:

根据手册页,dprintf 是 POSIX 扩展,不是标准库函数,因此在可移植性方面并不等同。

就它们在 GLIBC 中的实现而言,printfdprintf 都调用__vfprintf_internal,但请注意dprintf 也这样做(done != EOF &amp;&amp; _IO_do_flush (&amp;tmpfil.file) == EOF),它建议在写入后刷新缓冲区。 而printf 则不然。

我会尝试摆弄缓冲,即标准输出上的setbuffflush 或类似名称,看看是否有帮助。

【讨论】:

    猜你喜欢
    • 2019-11-11
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 2012-06-03
    • 2017-11-29
    • 2010-11-30
    • 2017-01-20
    • 2016-02-12
    相关资源
    最近更新 更多