为什么我程序中的 read() 系统调用会导致几种不同的可能结果?

Why does the read() system call in my program result in several different possible outcomes?

我无法准确理解 read() 的工作原理。例如,给定以下程序,文件 infile 包含字符串“abcdefghijklmnop”:

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

int main() {
   int fd;
   char buf[5] = "WXYZ";
   fd = open("infile", O_RDONLY);
   read(fd, buf, 2);
   read(fd, buf+2, 2);
   close(fd);
   printf("%c%c%c%c\n", buf[0], buf[1], buf[2], buf[3]);
   return 0;
}

查看read系统调用函数:

ssize_t read(int fildes, void *buf, size_t nbyte);

我知道 *buf 是保存读取字节的缓冲区,nbyte 是正在读取的字节数。所以在第一次 read() 之后,只有 infile 的前 2 个字符被读取(“a”和“b”)。为什么输出不只是“abcd”?为什么还有其他可能性,例如“aXbZ”或“abcZ”?

read 版本的手册页说:

read() attempts to read <i>nbyte</i> bytes of data from the object referenced by the descriptor <i>fildes into the buffer pointed to by <i>buf.

和:

Upon successful completion, read(), readv(), and pread() return the number of bytes actually read and placed in the buffer. The system guarantees to read the number of bytes requested if the descriptor references a normal file that has that many bytes left before the end-of-file, but in no other case.

因此,在您描述的情况下,“文件 infile 包含字符串“abcdefghijklmnop””,这两个 read 调用保证将“ab”和“cd”放入 buf,所以程序将打印“abcd”和一个换行符。 (我不会从字面上理解这个保证。当然系统可以保证它不会允许不相关的中断来阻止 read 完全读取请求的数据,但它不能保证没有硬件故障,例如磁盘驱动器在读取完成前发生故障。)

在其他情况下,当 read 从普通文件以外的源读取时,两个 read 调用中的每一个都可能读取 0、1 或 2 个字节。因此,可能的缓冲区内容是:

Bytes read in first read Bytes read in second read Buffer contents
0 0 WXYZ
0 1 WXaZ
0 2 WXab
1 0 aXYZ
1 1 aXbZ
1 2 aXbc
2 0 abYZ
2 1 abcZ
2 2 abcd