Home > Enterprise >  Is printf equivalent to dprintf(STDOUT_FILENO)?
Is printf equivalent to dprintf(STDOUT_FILENO)?

Time:11-30

I am learning something about PIPE in Linux, but I met something I can't figure out. I was reading rozmichelle's blog http://www.rozmichelle.com/pipes-forks-dups/#pipelines. The code below is to sort three words that parent process passes on to child process by 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;
}

In the code above, the parent process uses dprintf, but I wonder if we can redirect parent process' standard out to PIPE's in. So I tried to write the code below.

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

After redrecting, I used printf, which in my understanding will output to STDOUT. However, this code print nothing, while the first code print as below:

apple
peach
pear

I can't figure out why this happen, is there something I understand mistakely?

CodePudding user response:

According to man pages, dprintf is a POSIX extension, not a standard library function, so it is not equivalent in terms of portability.

As far as their implementation in GLIBC is concerned, both printf and dprintf call __vfprintf_internal, but note that dprintf does also this (done != EOF && _IO_do_flush (&tmpfil.file) == EOF) which suggests flushing the buffer after the write. printf, on the other hand, does not.

I'd try fiddling with buffering, i.e. setbuf, fflush or similar on the stdout and see if that helps.

  • Related