'bufp += nread;' 在鲁棒读取 rio_read() 函数中的作用是什么?

What the purpose of 'bufp += nread;' in the Robust reading rio_read() function?

提问人:Mary 提问时间:8/20/2023 最后编辑:Mary 更新时间:8/24/2023 访问量:81

问:

我正在阅读《计算机系统:程序员视角》一书中第 10 章中的代码。我理解下面的所有代码,除了以下行:bufp += nread;我发现这一行毫无意义,因为我看不出通过 nread 递增 bufp 指针的意义?

任何人都可以向我解释为什么 bufp+= nread;那里出口?谢谢!

ssize_t rio_readn(int fd, void *usrbuf, size_t n) 
{
    size_t nleft = n;
    ssize_t nread;
    char *bufp = usrbuf;

    while(nleft > 0) {
        if((nread = read(fd, bufp, nleft)) < 0) {
            if (errno == EINTR)
                nread = 0;
            else
                return -1;
        }
        else if (nread == 0)
            break;
        nleft -= nread;
        bufp += nread;
    }
    return (n - nleft);
}

我已经尝试了没有 bufp += nread; 的代码,它没有它就可以工作。我在网上到处搜索是否有人和我有同样的担忧,但我没有找到。

C IO 计算机科学 鲁棒

评论

0赞 Brian61354270 8/20/2023
您能谈谈您对什么的理解吗?另外,你是否了解目的和循环是什么?nread = read(fd, bufp, nleft)nleftwhile
0赞 Mary 8/20/2023
我想我弄清楚了:1)说在read()中间从文件中读取10个字节,读取3个字节后,read()返回-1的信号中断。2)但是你希望能够在中断后继续 read(),并且缓冲区 bufp 中已经存储了 3 个字节,分别是 usrbuf[0]、usrbuf[1]、usrbuf[2]。3) 因此,您通过设置 nread = 0 再次读取(),但将指针 *bufp 递增 nread/3 字节,因此 *bufp 指向缓冲区位置 &usrbuf[3],并且当再次调用 read() 时,bufp 缓冲区中已有的前 3 个 nread 字节不会被覆盖。

答:

4赞 Mark Adler 8/20/2023 #1

如果递增,则下一个将覆盖先前读取的数据。它的工作方式是提供字节,字节可能小于 .在第一次调用时,读取的数据会占用缓冲区位置。在 after 的下一次调用中,将指向 ,这是缓冲区中先前读取的内容之后的下一个可用字节。bufpread()read()nreadnleftusrbuf[0..nread-1]read()bufp += nread;bufpusrbuf[nread]

代码在没有增量的情况下工作的唯一原因是循环只运行一次,或者运行两次,第二次读取零字节。实际上,这两个是读取常规文件的正常情况,因为这样将获得所有可用数据。这个函数需要循环的原因是,当从管道读取时,不会等待来自源的字节,而是返回当时可用的字节。( 将等待至少一个字节或 EOF,因此,如果它返回零,您就知道它到达了 EOF。循环确保在字节最终从管道中可用时读取字节。read()read()read()nleftread()n

评论

0赞 Mary 8/20/2023
非常感谢您的评论,这对我来说很有意义。我认为我的代码之所以有效,是因为我立即在 read() 之后写了 write(),并且没有中断进化。
0赞 Luis Colorado 8/24/2023 #2

我已经尝试了没有 bufp += nread; 的代码,它没有它就可以工作。我在网上到处搜索是否有人和我有同样的担忧,但我没有找到。

当您进行部分读取(您尚未观察到的内容)并填充部分缓冲区时,并且将出现更多数据,您将创建一个新数据来尝试填充缓冲区的其余部分。我将尝试首先用注释解释循环中每个语句的含义。read()while

    while(nleft > 0) {  /* while there's still room in the buffer for more data */
        if((nread = read(fd, bufp, nleft)) < 0) {
            /* if nread  < 0, error checking must be done. */
            if (errno == EINTR)
                nread = 0; /* in case something interrupted the read, return
                            * 0, I have no clear idea if this is what is
                            * required, as some data can have been
                            * accumulated already, I should return n - nleft,
                            * as is done at the bottom, but can be fine,
                            * depending on the requirements.
                            */
            else
                return -1;  /* considered error, some data can be lost */
        }
        else if (nread == 0) /* nread == 0 is a special case (end of input) */
            break;
        /* now update the pointers to fill more space with another read if there's
         * still room in the buffer */
        nleft -= nread;  /* subtract the read from nleft to reflect the new
                          * available size in the buffer */
        bufp += nread;   /* advance the pointer nread positions, so next read
                          * doesn't overwrite the just read data */
    }
    return (n - nleft);  /* n - nleft is how much data has been read */

评论

0赞 Mary 8/25/2023
非常感谢您的评论,我认为您的评论与我上面对 Brian61354270 的回复相同。