为什么程序中调用read()系统调用会产生多种不同的输出结果?
read系统调用非预期输出原因分析
你出现这个问题的核心原因是对read()系统调用的行为理解有偏差:read()的第三个参数nbyte是单次调用最多读取的字节数上限,而非必须读取的字节数,实际读取的字节数由返回值决定,你没有对返回值做判断才会出现非预期结果。
首先明确read系统调用的完整行为
ssize_t read(int fildes, void *buf, size_t nbyte)的返回值含义如下:
- 大于0:实际读取到的字节数,这个值最多等于
nbyte,常见的小于nbyte的场景包括:读到文件末尾、读取的是慢速IO(比如管道、终端)时内核缓冲区中可用字节不足、读取过程被信号中断等 - 等于0:已经到达文件末尾
- 等于-1:读取出错,错误码存于errno中
对应你的程序场景拆解
你的程序初始化buf为"WXYZ",也就是初始状态下buf[0]='W'、buf[1]='X'、buf[2]='Y'、buf[3]='Z',infile内容为abcdefghijklmnop,结合不同的read返回情况就能对应你遇到的异常输出:
- 第一次
read(fd, buf, 2)仅返回1:仅buf[0]被覆盖为'a',buf[1]保持原有'X';第二次read(fd, buf+2, 2)仅返回1:仅buf[2]被覆盖为当前文件偏移对应的内容'b',buf[3]保持原有'Z',最终输出就是你提到的aXbZ - 第一次
read(fd, buf, 2)返回2:buf[0]='a'、buf[1]='b';第二次read(fd, buf+2, 2)仅返回1:buf[2]='c',buf[3]保持原有'Z',最终输出就是abcZ - 只有两次
read调用都恰好返回2的时候,才会输出你预期的abcd
正确实践
如果你的业务逻辑要求必须读满指定字节数才能继续,需要封装循环读的逻辑,比如:
ssize_t read_full(int fd, void *buf, size_t nbyte) { size_t total_read = 0; ssize_t cur_read; while (total_read < nbyte) { cur_read = read(fd, (char*)buf + total_read, nbyte - total_read); if (cur_read == 0) break; // 到达EOF if (cur_read == -1) return -1; // 出错 total_read += cur_read; } return total_read; }
每次读操作调用这个函数,再根据返回值判断是否读满即可避免这类问题。
内容的提问来源于stack exchange,提问作者justanotherstudent
相关产品推荐
相关产品推荐

