【发布时间】:2021-06-22 22:42:17
【问题描述】:
我想学习实现 cat 之类的功能,它只是从文件中获取输入并打印到标准输出。
但我不确定write() 的行是否在所有情况下都可靠,因为它可能写得少于n。但我无法创建一个测试用例来实现这种情况。如何制作一个测试用例,使其可以写入少于 n 个字符?另外,如何相应地修改代码以使程序健壮(对于这种情况,也适用于我没有描述的其他情况)?
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
const char *pathname = argv[1];
int fd;
if((fd = open(pathname, O_RDONLY)) == -1) {
perror("open");
return 1;
}
#define BUF_SIZE 1024
char buf[BUF_SIZE];
ssize_t n;
while((n = read(fd, &buf, BUF_SIZE)) > 0) {
if(write(STDOUT_FILENO, &buf, n) == -1) {
perror("write");
return 1;
}
}
if(n == -1) {
perror("read");
return 1;
}
if(close(fd) == -1) {
perror("close");
return 1;
}
return 0;
}
编辑:我根据 Armali 提到的管道阻塞测试用例修复了前面代码中的 write() 错误。谁能检查是否还有其他错误?
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
const char *pathname = argv[1];
int fd;
if((fd = open(pathname, O_RDONLY)) == -1) {
perror("open");
return 1;
}
#define BUF_SIZE 2*65536
char buf[BUF_SIZE];
ssize_t r_n;
while((r_n = read(fd, &buf, BUF_SIZE)) > 0) {
ssize_t w_n;
int i = 0;
while((w_n = write(STDOUT_FILENO, buf+i, r_n)) < r_n) {
if(w_n == -1) {
perror("write");
return 1;
}
r_n -= w_n;
i += w_n;
}
}
if(r_n == -1) {
perror("read");
return 1;
}
if(close(fd) == -1) {
perror("close");
return 1;
}
return 0;
}
【问题讨论】:
-
我没有看到您处理读取或写入的任何问题。 (实际上,您在验证每个步骤方面做得很好)为什么要使用系统调用而不是
stdio.hI/O? -
write有documented edge cases,其中可以写入的字节数少于n。在这些情况下,您的代码确实会失败。我能想象的可靠测试的唯一方法是模拟写入(可能通过宏)。 -
对于小于 2^31 字节数据的简单
cat程序,您尝试模拟的边缘情况并不常见。部分写入条件通常与网络写入相关联。在那里,您将循环直到写入n字节,以跟踪每次调用写入的数字。另一种情况是磁盘已满错误(不会发生写入stdout除非整个文件系统被其他东西填充(然后它将取决于实现)您对read的使用已经限制为@987654334 @ (1024字节) -
除此之外:将
&放在两个地方:while((n = read(fd, &buf, BUF_SIZE)) > 0) { if(write(STDOUT_FILENO, &buf, n) == -1) {。buf就足够了。 -
if(write(STDOUT_FILENO, &buf, n) == -1) {应该是if(write(STDOUT_FILENO, &buf, n) != n) {。