Подтвердить что ты не робот

Является ли возвращаемое значение 0 из записи (2) в C ошибкой?

На странице man для системного вызова write (2) -

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

он говорит следующее:

Возвращаемое значение

При успехе количество байтов (ноль указывает ничего не было написано). При ошибке -1 и errnoсоответственно. Если счетчик равен нулю и дескриптор файла относится к может быть возвращен обычный файл, 0 или ошибка может быть обнаружена. Для специального файл, результаты не переносятся.

Я бы интерпретировал это как означающее, что возвращение 0 просто означает, что ничего не было написано по какой-либо произвольной причине.

Однако Stevens в UNP рассматривает возвращаемое значение 0 как фатальную ошибку при работе с файловым дескриптором, являющимся сокетом TCP (это обертывается другой функцией, которая вызывает 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 как законное возвращаемое значение, если errno указывает, что вызов записи был прерван процессом, получающим сигнал.

Почему?

4b9b3361

Ответ 1

Стивенс, вероятно, делает это, чтобы поймать старые реализации write(), которые ведут себя по-разному. Например, Single Unix Spec говорит (http://www.opengroup.org/onlinepubs/000095399/functions/write.html)

Где этот объем IEEE Std 1003.1-2001 требует -1 для возврата, а errno - [EAGAIN], большинство исторические реализации возвращают ноль

Ответ 2

Кроме того, и просто для того, чтобы быть несколько педантичным здесь, если вы не пишете в сокет, я бы проверил, чтобы убедиться, что длина буфера ( "count" в первом примере) на самом деле вычисляется правильно. В примере Stevens вы даже не выполнили бы вызов write(), если длина буфера равнялась 0.

Ответ 3

Это гарантирует, что код не будет вращаться на неопределенный срок, даже если файловый дескриптор не является сокетом TCP или действуют неожиданные неблокирующие флаги. В некоторых системах некоторые устаревшие неблокирующие режимы (например, O_NDELAY) заставляют write() возвращать 0 (без установки errno), если никакие данные не могут быть записаны без блокировки, по крайней мере для определенных типов файловых дескрипторов. (В стандарте POSIX O_NONBLOCK используется возврат ошибки для этого случая.) И некоторые из неблокирующих режимов в некоторых системах относятся к базовому объекту (например, socket, fifo), а не файловому дескриптору, и поэтому даже могли быть включенным другим процессом, имеющим дескриптор открытого файла для того же объекта. Код защищает себя от завихрения в такой ситуации, просто рассматривая его как ошибку, поскольку он не предназначен для использования с неблокирующими режимами.

Ответ 4

Как говорит ваша справочная страница, возвращаемое значение 0 "не переносимо" для специальных файлов. Сокеты - это специальные файлы, поэтому результат может означать для них что-то другое.

Обычно для сокетов значение 0 байтов из read() или write() является индикатором того, что сокет закрыт, а после приема 0 последующие вызовы возвращают -1 с кодом ошибки.