I am reading this lecture and found this following code sample which I modified to this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main()
{
int fd;
char *s, *t;
off_t ret;
fd = open("file6", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (dup2(fd, 1) < 0) { perror("dup2"); exit(1); }
printf("Standard output now goes to file6\n");
s = "before close\n";
write(1, s, strlen(s));
close(fd);
printf("It goes even after we closed file descriptor %d\n", fd);
printf("%ld\t"
"%ld\n",
(long int) lseek(fd,0,SEEK_CUR),
(long int) lseek(1,0,SEEK_CUR));
s = "And fwrite\n";
fwrite(s, sizeof(char), strlen(s), stdout);
printf("%ld\t"
"%ld\n",
(long int) lseek(fd,0,SEEK_CUR),
(long int) lseek(STDOUT_FILENO,0,SEEK_CUR));
fflush(stdout);
s = "And write\n";
write(1, s, strlen(s));
printf("after:\tAnd wri...: lseek(fd,0,SEEK_CUR)=%ld\t"
"lseek(STDOUT_FILENO,0,SEEK_CUR)=%ld\n",
(long int) lseek(fd,0,SEEK_CUR),
(long int) lseek(STDOUT_FILENO,0,SEEK_CUR));
return 0;
}
I am sharing two different outputs with the only change in the code being that the line fflush(stdout) is commented out in first and present in the second run.
Output (with fflush(stdout) commented):
before close
And write
Standard output now goes to file4
It goes even after we closed file descriptor 3
-1 13
And fwrite
-1 13
after: And wri...: lseek(fd,0,SEEK_CUR)=-1 lseek(STDOUT_FILENO,0,SEEK_CUR)=23
Output with flush(stdout) uncommented:
before close
Standard output now goes to file4
It goes even after we closed file descriptor 3
-1 13
And fwrite
-1 13
And write
after: And wri...: lseek(fd,0,SEEK_CUR)=-1 lseek(STDOUT_FILENO,0,SEEK_CUR)=127
I have two questions:
- Why does "And write appears" first when fflush(stdout) is commented?
- Why lseek prints -1 which I checked separately is an error message corresponding to errno ESPIPE. I am aware that lseek on terminal results in an error. But my current understanding is that since the standard output is dup2 to file6, then, this error shouldn't arise? Shouldn't it (
lseek(STDOUT_FILENO, 0, SEEK_CUR)) simply return the current lseek pointer in file6, if dup2 is successful?
Because the C stdio buffers haven't filled, so nothing written using stdio APIs is actually sent to the output until the buffers fill, the stdio handle is flushed, or the program ends. Your direct
writecalls (e.g. for"And write") bypass stdio buffers entirely, and get written immediately, all the buffered stuff doesn't appear until the program ends (or at least, not until after"And write"has already been written).The first
lseekwas called onfd, which you closed shortly afterdup2ing it overSTDOUT_FILENO/1, so it fails. If you checked theerrnoproperly (zeroingerrnobefore eachlseek, calling the twolseeks separately and storing or printing their errors anderrnos separately, so one of them doesn't override theerrnoof the other before you even see it), you'd see it has a value corresponding toEBADF, notESPIPE. The secondlseekon (STDOUT_FILENO) works just fine. A mildly modified version of your code (usingstderrso you can see the output for the last couple outputs even when you can't read the actual file, carefully zeroingerrnoeach time, printing it before callinglseekagain, and usingstrerrorto show a friendly description of theerrno) shows this clearly: Try it online!