printf 是否等同于 dprintf(STDOUT_FILENO)?

Is printf equivalent to dprintf(STDOUT_FILENO)?

我正在 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,但我想知道我们是否可以将父进程的标准out重定向到PIPE的in。所以我尝试编写下面的代码。

#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;
}

redrecting 后,我使用了 printf,据我所知,它会输出到 STDOUT。但是,此代码不打印任何内容,而第一个代码打印如下:

apple
peach
pear

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

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

就它们在 GLIBC 中的实现而言,printfdprintf 都调用 __vfprintf_internal,但请注意 dprintf 也会调用 (done != EOF && _IO_do_flush (&tmpfil.file) == EOF)这建议在写入后刷新缓冲区。 printf,另一方面,没有。

我会尝试摆弄缓冲,即 setbuf, fflush 或标准输出上的类似内容,看看是否有帮助。