代码之家  ›  专栏  ›  技术社区  ›  Robert S. Barnes Antoni

C中写入(2)的返回值0是否为错误?

  •  13
  • Robert S. Barnes Antoni  · 技术社区  · 15 年前

    在系统调用的手册页中 write(2) -

    ssize_t write(int fd, const void *buf, size_t count);

    上面写着:

    返回值

    成功时,字节数 返回写入(零表示 什么都没有写)。关于错误,-1是 返回,以及 errno 已设置 适当地。如果计数为零并且 文件描述符引用 常规文件,可以返回0,或者 可能检测到错误。为了特殊 文件,结果不可移植。

    我会把这解释为返回0仅仅意味着没有任何东西被写,不管是出于什么武断的原因。

    然而, Stevens in UNP 处理TCP套接字的文件描述符时,将返回值0视为致命错误(它由另一个调用 exit(1) 在短时间内):

    ssize_t /* Write "n" bytes to a descriptor. */
    writen(int fd, const void *vptr, size_t n)
    {
        size_t      nleft;
        ssize_t     nwritten;
        const char  *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
                if (nwritten < 0 && errno == EINTR)
                    nwritten = 0;       /* and call write() again */
                else
                    return(-1);         /* error */
            }
    
            nleft -= nwritten;
            ptr   += nwritten;
        }
        return(n);
    }
    

    他只将0视为合法的返回值,如果 埃尔诺 指示接收信号的进程中断了写入调用。

    为什么?

    4 回复  |  直到 15 年前
        1
  •  7
  •   Per Knytt    15 年前

    史蒂文斯这样做可能是为了抓住 行为不同的write()。例如,单个Unix规范 说( http://www.opengroup.org/onlinepubs/000095399/functions/write.html )

    这里是IEEE标准的本卷 1003.1-2001要求返回-1并将errno设置为[eagain],大多数 历史实现返回零

        2
  •  3
  •   mark4o    15 年前

    这将确保代码不会无限旋转,即使文件描述符不是TCP套接字或意外的非阻塞标志生效。在某些系统上,某些传统的非阻塞模式(例如 O_NDELAY 原因 write() 返回0(不设置 errno )如果没有数据可以在不阻塞的情况下写入,至少对于某些类型的文件描述符是如此。(POSIX标准 O_NONBLOCK 在这种情况下使用错误返回。)并且某些系统上的一些非阻塞模式应用于底层对象(例如socket、fifo),而不是文件描述符,因此甚至可以由另一个为同一对象打开文件描述符的进程启用。在这种情况下,代码通过简单地将其视为一个错误来保护自己,因为它不用于非阻塞模式。

        3
  •  1
  •   bobp    15 年前

    另外,为了在这里稍微有点迂腐,如果您不在编写套接字,我将检查以确保缓冲区长度(在第一个示例中为“count”)实际上是正确计算的。在stevens示例中,如果缓冲区长度为0,则甚至不会执行write()调用。

        4
  •  0
  •   SoapBox    15 年前

    正如您的手册页所说,返回值0对于特殊文件是“不可移植的”。套接字是特殊文件,因此结果可能对它们意味着不同的东西。

    通常对于套接字,read()或write()中的0字节值表示套接字已关闭,接收到0后,后续调用将返回-1并返回错误代码。