dup2 and printf

1.the code is shown below:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main()
{
int fd1=open("eup.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if(fd1==-1){
printf("#LINE %d:",__LINE__);
perror("open");
return -1;
}
//printf("Hello, World!\n");
int fd2=dup2(fd1,1);
if(fd2==-1){
printf("#LINE %d:",__LINE__);
perror("open");
return -1;
}
printf("fd1:%d\nfd2:%d\nfd3:%d\n",fd1,fd2,3);
close(fd2);
close(fd1);
return 0;
}
2. the questions are:
why annotated "printf("Hello, World!\n");" ,the file "eup.txt" is empty?
why not annotated "printf("Hello, World!\n");" ,the file "eup.txt" is not empty?
the content is as below:
fd1:4
fd2:1
fd3:3

who knows??
Last edited on
Can you please use the code format tags around your code. It's not easy to read the code, even though it's a 15 line program. You can do so by editing the original post.

The real question is, what does dup2 do? Have you looked at the man page?
https://www.man7.org/linux/man-pages/man2/dup.2.html

The text says:
The dup() system call creates a copy of the file descriptor oldfd,
using the lowest-numbered unused file descriptor for the new
descriptor.

After a successful return, the old and new file descriptors may be
used interchangeably.
...
The dup2() system call performs the same task as dup(), but instead
of using the lowest-numbered unused file descriptor, it uses the file
descriptor number specified in newfd. If the file descriptor newfd
was previously open, it is silently closed before being reused.

To go forward:
Does any of this mean anything to you?
Do you know what a file descriptor is?
Do you know what file descriptor 1 is?
first thanks.
I know file descriptor. In my code, stdout redirect to the file(eup.txt).Then, all output will write to the file(eup.txt).
I don't understand two questions:
first :
when not annotated printf("Hello, World!\n");
,then run the program, the file(eup.txt) is not empty.Who flushed the file buffer?
second:
when annotated printf("Hello, World!\n");
,then run the program, this file is empty. In this cae, the file buffer is not fflushed.Beacause "\n" can not fflush the file buffer ,so the file is empty.
What's so hard to understand?

printf's to stdout before the dup2() call can't possibly end up in the file.

Any more than you would expect to see 42 printed here.
1
2
3
int x = 5;
printf("%d\n",x);
x = 42;
I know file descriptor. In my code, stdout redirect to the file(eup.txt).
prinft() doesn't write to the screen. It writes to file descriptor 1. It's just that stdout is arranged to go to the terminal to begin with.

When a program starts, it inherits 3 streams, represented by file descriptors; stdin(0), stdout(1), stderr(2). You are free to close these if you don't want them, and if you do, then start opening files or make socket connections, these file descriptors will be reused.

A file descriptor is just an index into an array of file-like stuff in the kernel.

printf() writes to stdout by writing to file descriptor 1. If you change file descriptor 1 to represent a file, the output will go to a file, or if your change it to represent a tcp client connection, the output will down the network.

Having said that, I suggest you re-read the extract of that man page. Feel free to come back if you don't understand, or have further questions.

Regarding the stuff you've most recently asked:
1. Who flushed the file buffer?
I'm not sure which buffer you mean. It doesn't really have any baring on the issue.

2. In this cae, the file buffer is not fflushed ...
Calling close() on a file descriptor flushes any data. If you forget to call close and the program terminates normally, close will be called for you. Again, these things aren't relevant here.
Last edited on
I'm not sure which buffer you mean. It doesn't really have any baring on the issue.
Actually this may have everything to do with it. It depends on whether stdout is line buffered by default. Let's look at the code with indentation and code tags:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int
main()
{
    int fd1 = open("eup.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd1 == -1) {
        printf("#LINE %d:", __LINE__);
        perror("open");
        return -1;
    }
    printf("Hello, World!\n");
    int fd2 = dup2(fd1, 1);
    if (fd2 == -1) {
        printf("#LINE %d:", __LINE__);
        perror("open");
        return -1;
    }
    printf("fd1:%d\nfd2:%d\nfd3:%d\n", fd1, fd2, 3);
    close(fd2);
    close(fd1);
    return 0;
}

Line 15 buffers the data, so if may be written to the old fd1, or the new one, depending on when the data gets flushed.

Line 22 buffers the data.

Line 23 closes fd1, but the buffered data might not have been written yet, so it might be lost.

To test this I added this to the beginning of main() to fully buffer stdout:
1
2
    char buf[2000];
    setvbuf(stdout, buf, _IOFBF, sizeof(buf));

As expected, I received no output whatsoever to either the old stdout or the new one.

If you're going to muck around with the UNIX file descriptors then you need to be sure that that the C library buffered I/O is flushed when you need it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int
main()
{
    // set full buffering
    char buf[2000];
    setvbuf(stdout, buf, _IOFBF, sizeof(buf));
    int fd1 = open("eup.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
    if (fd1 == -1) {
	printf("#LINE %d:", __LINE__);
	perror("open");
	return -1;
    }
    printf("Hello, World!\n");
    fflush(stdout);		// flush stdout to fd 1
    int fd2 = dup2(fd1, 1);
    if (fd2 == -1) {
	printf("#LINE %d:", __LINE__);
	perror("open");
	return -1;
    }
    printf("fd1:%d\nfd2:%d\nfd3:%d\n", fd1, fd2, 3);
    fclose(stdout);		// flush and close
    close(fd1);
    return 0;
}



Mixing C runtime buffered i/o with OS unbuffered i/o; ok yeah, I missed that one. That's asking for trouble.
Last edited on
Registered users can post here. Sign in or register to post.