UNIX读取行为

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

#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 

为什么阅读的行为是这样的?

请注意, lseek返回的值是off_t ,而不是size_t 。 不同的是,off_t是签名的。 当你采取一个有符号的值并使其无符号时,它看起来像一个很大的正数。

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

换句话说,你从lseek得到一个错误。

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

在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 

两者似乎都是合理的回应