如果使用lseek(),为什么文件描述符上的read()会失败?

时间:2016-10-12 03:54:35

标签: c file-io io posix

在以下示例中,我们关闭默认stderr并使用描述符fdopen()通过2在临时文件上重新打开它,dup()来自write()临时文件描述符。然后我们2直接到此描述符fprintf()。我们可以安全地执行此操作,因为它是文件上的第一个写操作,因此它具有空缓冲区。在此之后,我们stderr到新的stderr。然后我们关闭2(因此,其关联的描述符fd将自动关闭)。原始描述符#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> int main(void) { int fd; char buf[200]; int n; char fname[] = "/tmp/tst-perror.XXXXXX"; fd = mkstemp (fname); fclose (stderr); dup2 (fd, 2); stderr = fdopen (2, "w"); fd = fileno(stderr); char *s = "this is a test\n"; n = write(fd, s, strlen(s)); fprintf(stderr, "multibyte string\n"); fclose (stderr); // close(fd); // fd = open(fname, O_RDONLY); lseek (fd, 0, SEEK_SET); n = read (fd, buf, sizeof (buf)); printf("%.*s", (int) n, buf); close (fd); return 0; } 仍然有效。通过它我们转到临时文件的开头,读取其内容并将它们打印到stdout。但输出是乱码:

$ ./a.out
����

输出结果为:

$ ./a.out
this is a test
multibyte string

如果我们取消注释&#34;关闭&#34;和&#34;打开&#34;线条和评论&#34; lseek&#34;行,输出符合预期:

write()

stderr没有缓冲区,<% ... %>在关闭时被注销,所以 如果我们在阅读之前没有关闭文件,为什么输出会出现乱码?

1 个答案:

答案 0 :(得分:1)

没有检查函数的返回值。如果它在那里你会发现错误。

无论如何,问题是:

  fd = fileno(stderr);     // getting the fd from current stderr
  fclose (stderr);         // closing stderr
  ...
  lseek (fd, 0, SEEK_SET); // seeking on fd which was already closed

在最后一次调用和后续调用fd实际上是未定义的(或者它引用了封闭文件描述符)。因此fd上的任何操作都将失败EBADF(无效的文件描述符)。

显然,如果再次添加fd = open(...)fd将变为有效且代码可以正常运行。