首页 > 解决方案 > 为什么我的程序中的 read() 系统调用会导致几种不同的可能结果?

问题描述

我在理解 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;
}

查看读取系统调用函数:

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

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

标签: cio

解决方案


我的版本的手册页read说:

read()尝试nbyte从描述符引用的对象中读取字节数据到 .fildes指向的缓冲区中buf

和:

成功完成后,返回read()实际读取并放入缓冲区的字节数。如果描述符引用了一个在文件结尾之前剩余那么多字节的普通文件,则系统保证读取请求的字节数,但在其他情况下不会。readv()pread()

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

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

首次读取的字节数 第二次读取的字节数 缓冲区内容
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

推荐阅读