Given the following code, I have: printf("hello\n");
so I am expecting to see hello\n
in myfile
. but when I run my program I see haha
which means \n
was ignored, why is that?
Worth Noting: when I replace printf("hello\n");
with printf("hellos");
I don't see the s
letter being printed as well. So I think maybe something is writing on top of it but the question is who and why?
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <string.h>
int main() {
// creates a new file having full read/write permissions
int fd = open("myfile", O_RDWR | O_CREAT, 0666);
write(fd, "haha\n", 5);
close(fd); // line 6
fd = open("myfile", O_RDWR); // line 7
close(0);
close(1);
dup(fd);
dup(fd);
if (fork() == 0) {
char s[100];
dup(fd);
scanf("%s", s);
printf("hello\n");
write(2, s, strlen(s)); // line 18
return 0; // line 19
}
wait(NULL);
printf("Father finished\n");
close(fd);
return 0;
}
contents of myfile after running:
haha
helloFather finished (new line after this)
First of all, the behavior is undefined. You are starting to use stdout
that refers to the same file descriptor as stdin
without closing or flushing stdin
before doing it. Let's try to take the important stuff from POSIX 2.5.1 Interaction of File Descriptors and Standard I/O Streams:
[...] if two or more handles are used, and any one of them is a stream, the application shall ensure that their actions are coordinated as described below. If this is not done, the result is undefined.
[...]
For a handle to become the active handle, the application shall ensure that the actions below are performed between the last use of the handle (the current active handle) and the first use of the second handle (the future active handle). [...]
[...]
For the first handle, the first applicable condition below applies. [...]
[...]
If the stream is open with a mode that allows reading and the underlying open file description refers to a device that is capable of seeking, the application shall either perform an fflush(), or the stream shall be closed.
Your code does:
scanf("%s", s); // associates stdin with fd
// Ups - no flush(stdin) nor fclose(stdin)
printf("hello\n"); // associates stdout with fd - undefined behavior
The result you are seeing comes from that scanf
calls ungetc
which increments file position but also "remembers" to un-increment file position once the stream is flushed. Because it is flushed when child terminates, the file position is decremented, and parent overwrites last character of the child.