【问题标题】:Calling system call read leads to infinite loop调用系统调用读取导致无限循环
【发布时间】:2018-02-10 21:39:27
【问题描述】:

我想制作一个非常简单的控制台应用程序来替换 Unix 命令wc -c。为此,我只需要简单地计算文件中的字节数并在控制台中输出它们。

如果我的应用程序没有提供参数,它会从标准输入中读取它们(这部分我已经开始工作了)。但是,如果我决定提供更多参数(有效的和现有的文件名),我应该计算每个参数的字节数。

到目前为止一切顺利。这是代码

const int __OPEN_ERROR = 48;

int main(int argc, char* argv[]) {

    if(argc == 1) {
        char buf[3];
        int count = 0, lines = 0;
        while(read(0, buf, 1) != 0) {
            count++;
            if(buf[0] == '\n')
                lines++;
        }

        printf("Count:%d\n", count);
        printf("Lines:%d\n", lines);
    }
    else {
        int fd, bytes = 0;
        char buf[3];

        for (int arg = 1; arg <= argc; arg++) {
            if ((fd = open(argv[arg], O_RDONLY) < 0)) {
                exit(__OPEN_ERROR);
            }
            while (read(fd, buf, 1) != 0) { // <-- this here leads to infinite loop.
                printf("%s", buf);
                bytes++;
            }

            printf("%d %s", bytes, argv[arg]);
        }
    }

    exit(0);
}

请不要介意这段代码写得有多糟糕,这是我探索 C 的第一天,现在我想要的一切都是可行的解决方案。

请注意两个读取是如何相同的,但后一个会陷入无限循环,原因我无法理解。是的,打开文件成功了。

【问题讨论】:

  • readopen 可以返回 -1(失败时)。你需要处理这种情况。 仔细阅读open(2)read(2)errno(3)
  • argv[argc]始终为空指针。然而你试图用它来打开一个文件。
  • arg &lt;= argc 应该是arg &lt; argc
  • printf("%s", buf) 导致未定义的行为,因为buf 中没有空终止符。
  • Tangential:请注意,通常不应创建以下划线开头的函数或变量名称。 C11 §7.1.3 Reserved identifiers 说: — 所有以下划线开头的标识符以及大写字母或另一个下划线始终保留用于任何用途。所有以下划线开头的标识符始终保留用于在普通名称空间和标记名称空间中用作具有文件范围的标识符。 另请参阅What does double underscore (__const) mean in C?

标签: c unix file-descriptor


【解决方案1】:

你的循环错了,应该是:

char buf;
...
while (read(fd, buf, 1) == 1) {
    printf("%c", buf);
    bytes++;
}

read 允许您从文件描述符中读取字节。给定的数字说n 是一个请求,这意味着read 最多读取n 字节,返回的值正是有效读取的字节数。当您想读取 1 个字节时,请测试它是否读取 1 个字节。其次,当您逐个读取字节(或字符)时,结果是一个字符并且应该打印为。 %c 告诉 printf 将值打印为字符(%s 是打印 C 字符串)。

另一个错误是arg循环的控制,应该是:

for (int arg = 1; arg < argc; arg++) // strict test...arg from 0 to argc-1 (included) or argc (excluded)

您还必须在每个 arg 循环中将字节数重置为 0,并关闭每个未使用的文件,因此:

for (int arg = 1; arg < argc; arg++) {
    char buf;
    int bytes = 0;
    int fd;
    if ((fd = open(argv[arg], O_RDONLY) < 0)) {
        exit(__OPEN_ERROR);
    }
    while (read(fd, buf, 1) == 1) {
        printf("%c", buf); // optionnal, counting may not print...
        bytes++;
    }
    close(fd);
    printf("%d %s", bytes, argv[arg]);
}

【讨论】:

    猜你喜欢
    • 2021-06-12
    • 2011-08-23
    • 1970-01-01
    • 2020-09-15
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 1970-01-01
    相关资源
    最近更新 更多