Question

Here is my code:

#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
int main(int argc,char *argv[])
{
  int oldfd;
  int newfd;
  if(argc!=2)
  {
    printf("Usgae : %s file_name\n",argv[0]);
    exit(0);
  }
 oldfd=open(argv[1],O_RDWR|O_APPEND,S_IRWXU); // Opening the file in Read/Write mode
 if (-1 == oldfd)
 {
  perror("Error opening file");
  exit(0);
 }
 close(1); // closing stdout 
 newfd=dup(oldfd); //Now this newfd holds the value 1 
 close(oldfd); //closing the oldfd
 printf("\nStack Overflow"); //Now this printf will print content into the file as stdout closed already
 close(newfd);// closing newfd 
 return 0;
}

What I'm actually trying to do is just printing "Stack Overflow" to the file using printf() instead of write() system call.

Its not printing the content into the file. But one thing i observed is that if i remove the code:

 close(newfd)

It's printing the contents into the file as expected. But I can't understand why. I printed the contents and then only I'm closing the newfd.

Whats the reason for this?

Was it helpful?

Solution

What's actually happening here is that printf's output is buffered and not sent to fd 1 immediately; instead the buffer is flushed to file descriptor 1 by the C run-time after you return from main. If you close(newfd), you've effectively obstructed the automatic flush that is otherwise performed by the run-time at exit.

If you explicitly fflush(stdout) before you close(newfd), your output should appear in the file.

By the way, if you want to redirect a specific file descriptor, there is an alternate system call dup2(oldfd, 1) which makes fd 1 a duplicate of oldfd, closing fd 1 if it was previously open.

OTHER TIPS

When you're using file descriptors directly, you will want to avoid using the C stdio functions such as printf. Changing the underlying file descriptor out from under the stdio layer seems fraught with peril.

If you change your printf to the following:

write(newfd, "\nStack Overflow", 15);

then you will probably get the output you expect (whether your close(newfd) or not).

close, write, open are system calls mostly done inside the linux kernel; so from the application point of view, they are elementary atomic operations.

printf and fprintf are standard library functions built above these (and others) syscalls.

Before exit-ing (e.g. returning from main), the standard library and environment (in particular the code in crt*.o calling your main) is executing the functions registered by atexit; and the standard I/O is (sort-of) registering a call to fflush at exit time. So the stdout is fflush-ed at exit time. If you close its descriptor in main, that flush fails and do nothing.

I think you should not mix stdio and raw write-s to the same write descriptor. Consider using fdopen or freopen

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top