Является ли возвращаемое значение 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
указывает, что вызов записи был прерван процессом, получающим сигнал.
Почему?
Ответы
Ответ 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 с кодом ошибки.