Стандарт C требует, чтобы никакие функции стандартной библиотеки C не устанавливались errno
в ноль. Почему именно это?
Я мог бы понять, что это полезно для вызова нескольких функций и проверки только errno
после последней, например:
errno = 0;
double x = strtod(str1, NULL);
long y = strtol(str2, NULL);
if (errno)
// either "strtod" or "strtol" failed
else
// both succeeded
Однако не считается ли это "плохой практикой"? Так как вы только проверка errno
в самом конце, вы знаете только , что одна из функций действительно терпят неудачу, но не которые функционируют не удалось. Просто знание того, что что- то не получилось достаточно хорошо для большинства практических программ?
Я пытался найти различные документы C Rationale, но у многих из них нет подробностей <errno.h>
.
errno
, вы всегда можете установить его на ноль самостоятельно.errno
ненулевое значение, даже если это удастся. (Это может вызвать другую функцию, которая не работает, но это не является ошибкой во внешней функции.)Ответы:
Библиотека C не устанавливается
errno
в 0 по историческим причинам 1 . POSIX больше не утверждает, что его библиотеки не изменят значение в случае успеха, и новая справочная страница Linux дляerrno.h
отражает это:ANSI C Обоснование утверждает , что Комитет счел более целесообразным принять и стандартизировать существующую практику использования
errno
.Почти всегда есть способ проверить на наличие ошибок, кроме проверки, если
errno
она установлена. Проверка,errno
получен ли набор, не всегда надежен, поскольку некоторые вызовы требуют вызова отдельного API, чтобы получить причину ошибки. Например,ferror()
используется для проверки ошибки, если вы получаете короткий результат отfread()
илиfwrite()
.Интересно, что ваш пример использования
strtod()
- это один из случаев, когда для правильного обнаружения возникновения ошибки требуется установитьerrno
значение 0 перед вызовом . Все функции со строкой в число имеют это требование, потому что верное возвращаемое значение возвращается даже в случае ошибки.strto*()
Приведенный выше код основан на поведении, описанном
strtod()
в Linux . Стандарт C предусматривает только то, что underflow не может возвращать значение, превышающее наименьшее положительное значениеdouble
, иerrno
задано или нет значение,ERANGE
определенное реализацией 2 .На самом деле существует обширная консультативная запись сертификата, которая рекомендует всегда устанавливать
errno
значение 0 перед вызовом библиотеки и проверять его значение после вызова, чтобы указать, что произошла ошибка . Это связано с тем, что некоторые вызовы библиотеки будут установлены,errno
даже если сам вызов был успешным 3 .1. Ранее я утверждал, что это было во избежание маскировки ошибки от более раннего вызова. Я не могу найти никаких доказательств в поддержку этого утверждения. У меня также был фиктивный
printf()
пример.2. Спасибо @chux за указание на это. Ссылка C.11 §7.22.1.3 ¶10.
3. Указано @KeithThompson в комментарии.
источник
errno
вERANGE
- это реализация, определенная в случае недостаточного значения, на самом деле нет никакого портативного способа обнаружения недостаточного значения. Мой код соответствовал тому, что я нашел на странице руководства Linux в моей системе.strto*
функциях - именно поэтому я и спросил, будет ли мой пример считаться плохой практикой, но это единственный способ, при которомerrno
отсутствие нуля было бы полезно или даже применимо.errno
может быть установлено даже в случае успеха, поэтому просто использование того факта, что оно установлено, не является достаточно хорошим индикатором того, что произошла ошибка. Вы должны сами проверить результаты отдельных звонков, чтобы узнать, произошла ли вообще ошибка.Вы можете сделать проверку ошибок для обоих вызовов функций, если вы действительно заботитесь об этом.
Поскольку мы никогда не знаем, как функция mach вызывается в процессе, как библиотека может устанавливать errnos для каждого вызова функции, верно?
источник
Произвольное изменение errorno аналогично «отлову и проглатыванию» исключения. До того, как были исключения, которые распространялись через разные уровни программы и, наконец, достигали точки, когда вызывающая сторона либо ловила и реагировала на исключение тем или иным способом, либо просто передавала деньги, были ошибки. Не изменяйте ошибку, если только вы не обрабатываете, не переопределяете, не рассматриваете ошибку как несущественную, что существенно для этой парадигмы распространения ошибок первого поколения.
источник