intricacies/understanding stdio 缓冲区和 dup2
intricacies/understanding the stdio buffer and dup2
我正在阅读这篇文章 lecture 并发现了以下我修改过的代码示例:
#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;
}
我共享两个不同的输出,代码中唯一的变化是 fflush(stdout)
行在第一个被注释掉并出现在第二个 运行.
输出(注释 fflush(stdout)
):
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
带 flush(stdout) 的输出未注释:
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
我有两个问题:
- 为什么在注释 fflush(stdout) 时首先出现“And write”?
- why lseek prints -1 这个我单独查的是errno ESPIPE对应的错误信息。我知道终端上的 lseek 会导致错误。但是我目前的理解是,既然标准输出是dup2 to file6,那么,应该不会出现这个错误吧?如果 dup2 成功,它 (
lseek(STDOUT_FILENO, 0, SEEK_CUR)
) 不应该只是 return 文件 6 中的当前 lseek 指针吗?
Why does "And write" appear first when fflush(stdout) is commented?
因为 C stdio 缓冲区尚未填满,所以在缓冲区填满、stdio 句柄被刷新或程序结束之前,使用 stdio API 编写的任何内容都不会实际发送到输出。您的直接 write
调用(例如 "And write"
)完全绕过 stdio 缓冲区,并立即写入,直到程序结束(或者至少,直到 [=11 之后),所有缓冲的内容才会出现=] 已经写过了)。
Why lseek prints -1?
第一个 lseek
是在 fd
上调用的,您在 dup2
在 STDOUT_FILENO
/1
上调用它后不久就关闭了,所以它失败了。如果您正确检查了 errno
(在每个 lseek
之前将 errno
归零,分别调用两个 lseek
并分别存储或打印它们的错误和 errno
,所以它们中的一个在你看到它之前不会覆盖另一个的 errno
),你会看到它的值对应于 EBADF
,而不是 ESPIPE
。 (STDOUT_FILENO
) 上的第二个 lseek
工作得很好。代码的轻微修改版本(使用 stderr
因此即使您无法读取实际文件,您也可以看到最后几个输出的输出,每次仔细地将 errno
归零,在调用之前打印它再次 lseek
,并使用 strerror
显示 errno
) 的友好描述,清楚地表明:Try it online!
我正在阅读这篇文章 lecture 并发现了以下我修改过的代码示例:
#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;
}
我共享两个不同的输出,代码中唯一的变化是 fflush(stdout)
行在第一个被注释掉并出现在第二个 运行.
输出(注释 fflush(stdout)
):
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
带 flush(stdout) 的输出未注释:
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
我有两个问题:
- 为什么在注释 fflush(stdout) 时首先出现“And write”?
- why lseek prints -1 这个我单独查的是errno ESPIPE对应的错误信息。我知道终端上的 lseek 会导致错误。但是我目前的理解是,既然标准输出是dup2 to file6,那么,应该不会出现这个错误吧?如果 dup2 成功,它 (
lseek(STDOUT_FILENO, 0, SEEK_CUR)
) 不应该只是 return 文件 6 中的当前 lseek 指针吗?
Why does "And write" appear first when fflush(stdout) is commented?
因为 C stdio 缓冲区尚未填满,所以在缓冲区填满、stdio 句柄被刷新或程序结束之前,使用 stdio API 编写的任何内容都不会实际发送到输出。您的直接 write
调用(例如 "And write"
)完全绕过 stdio 缓冲区,并立即写入,直到程序结束(或者至少,直到 [=11 之后),所有缓冲的内容才会出现=] 已经写过了)。
Why lseek prints -1?
第一个 lseek
是在 fd
上调用的,您在 dup2
在 STDOUT_FILENO
/1
上调用它后不久就关闭了,所以它失败了。如果您正确检查了 errno
(在每个 lseek
之前将 errno
归零,分别调用两个 lseek
并分别存储或打印它们的错误和 errno
,所以它们中的一个在你看到它之前不会覆盖另一个的 errno
),你会看到它的值对应于 EBADF
,而不是 ESPIPE
。 (STDOUT_FILENO
) 上的第二个 lseek
工作得很好。代码的轻微修改版本(使用 stderr
因此即使您无法读取实际文件,您也可以看到最后几个输出的输出,每次仔细地将 errno
归零,在调用之前打印它再次 lseek
,并使用 strerror
显示 errno
) 的友好描述,清楚地表明:Try it online!