【问题标题】:UNIX read behaviorUNIX 读取行为
【发布时间】:2013-01-14 22:29:55
【问题描述】:

我编写了这个小代码来确定读取行为。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>

int main ()
{
  ssize_t ret;
  int fd;
  char str[30] = {0};
  off_t lret

  fd = open("./sample", O_RDWR);
  printf("File descriptor = %d\n",fd);

  lret = lseek(fd,LONG_MAX,SEEK_SET);
  printf("%ld\n",lseek(fd, 0, SEEK_CUR));

  ret = read(fd, str, 20);
  if (ret == -1) {
     perror("read error");
  }
  else {
     printf("%ld\n",ret);
     printf("%s\n",str);
  }

  ret = write(fd, "bye", 3);
  if (ret == -1) {
     perror("write error");
  }
  else
     printf("%ld\n",ret);

  printf("%ld\n",lseek(fd, 0, SEEK_CUR));
  close (fd);

  return 0;
}

这是输出:

$ cat sample
HELLO$ ./a.out
File descriptor = 3
4294967295
read error: Invalid argument
write error: Invalid argument
4294967295
$ ll sample
-rw-r--r--. 1 bruce stud 5 Jan 14 17:25 sample

但如果我将 lseek 语句更改为

ret = lseek(fd,5,SEEK_SET);

读取返回 0

$ ./a.out
File descriptor = 3
5
0

3
8
$ cat sample
HELLObye$ ll sample
-rw-r--r--. 1 bruce stud 8 Jan 14 17:26 sample

为什么 read 会有这样的行为?

【问题讨论】:

  • 你需要64位读/写I/O

标签: c linux unix


【解决方案1】:

注意lseek 返回的值是off_t,而不是size_t。不同之处在于 off_t 是有符号的。当您取一个有符号值并使其无符号时,它看起来像一个很大的正数。

我希望“LONG_MAX”实际上不是4294967295,而是2147483647 (2^31-1) 或更大的数字。所以4294967295 来自-1 [它是2^32-1,这确实与32 位数学中的-1 相同]。

换句话说,您收到来自lseek 的错误。

【讨论】:

  • ssize_t 也已签名,例如 off_t。但是,它可能与off_t 的大小不同,并且两者都可能与long 不同。
  • 在我的系统上,ssize_t 和 off_t 都是 8 个字节长。 # 定义 LONG_MAX 9223372036854775807L
  • 这里的重点不是off_t的大小,而是off_t有签名而size_t没有。
  • 好的。这是我所做的: off_t lret; lret = lseek(fd,LONG_MAX,SEEK_SET); if (lret == -1) perror("寻找错误");我得到“寻求错误:成功”
  • 你如何解释 printf("%ld\n",lseek(fd, 0, SEEK_CUR)); 的值是4294967295。如果seek出现错误,文件指针的值应该是0,对吧?
【解决方案2】:

奇怪的错误结果。您使用的是什么实际操作系统?我在第一次 lseek 之后添加了一个检查 if (ret == -1) perror("lseek error");,以便更好地检查错误。

在 linux 上我看到了:

File descriptor = 3
lseek error: Invalid argument
0
5
HELLO
3
8

在 OpenBSD 上我看到了:

File descriptor = 3
9223372036854775807
read error: File too large
write error: File too large
9223372036854775807

...这两个似乎都是合理的回应

【讨论】:

  • lseek 的返回类型为 off_t,在我的系统上为 8 个字节。 ret 是 int 类型。这就是它在 lseek 上打印错误的原因。 lseek 上其实没有错误。
  • 我认为当您在 Linux 上运行时,第一种情况下 write 会成功。我想看看我是否超过了最大文件大小,读写时会发生什么。如果我寻求超过文件大小(不是最大文件大小),读取返回 0。我认为它也应该在这里返回 -1。
猜你喜欢
  • 2019-11-23
  • 1970-01-01
  • 2021-09-28
  • 2017-09-30
  • 1970-01-01
  • 2023-03-15
  • 2011-01-01
  • 2012-04-09
  • 1970-01-01
相关资源
最近更新 更多