Библиотека C не устанавливается errno
в 0 по историческим причинам 1 . POSIX больше не утверждает, что его библиотеки не изменят значение в случае успеха, и новая справочная страница Linux дляerrno.h
отражает это:
<errno.h>
Файл заголовка определяет целочисленную переменную errno
, которая устанавливается с помощью системных вызовов и библиотечные функции в случае ошибки , чтобы указать , что пошло не так. Его значение имеет значение только тогда, когда возвращаемое значение вызова указывает на ошибку (т. Е. -1
От большинства системных вызовов -1
или NULL
от большинства функций библиотеки); Успешная функция может измениться errno
.
ANSI C Обоснование утверждает , что Комитет счел более целесообразным принять и стандартизировать существующую практику использования errno
.
Механизм сообщения об ошибках, сконцентрированный на настройке, errno
обычно рассматривается в лучшем случае с допуском. Это требует «патологической связи» между библиотечными функциями и использует статическую ячейку памяти с возможностью записи, что мешает созданию разделяемых библиотек. Тем не менее Комитет предпочел стандартизировать этот существующий, однако несовершенный механизм, а не изобретать что-то более амбициозное.
Почти всегда есть способ проверить на наличие ошибок, кроме проверки, если errno
она установлена. Проверка, errno
получен ли набор, не всегда надежен, поскольку некоторые вызовы требуют вызова отдельного API, чтобы получить причину ошибки. Например, ferror()
используется для проверки ошибки, если вы получаете короткий результат от fread()
или fwrite()
.
Интересно, что ваш пример использования strtod()
- это один из случаев, когда для правильного обнаружения возникновения ошибки требуется установить errno
значение 0 перед вызовом . Все функции со строкой в число имеют это требование, потому что верное возвращаемое значение возвращается даже в случае ошибки.strto*()
errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
/*...parse error */
} else if (errno == ERANGE) {
if (x == 0) {
/*...underflow */
} else if (x == HUGE_VAL) {
/*...positive overflow */
} else if (x == -HUGE_VAL) {
/*...negative overflow */
} else {
/*...unknown range error? */
}
}
Приведенный выше код основан на поведении, описанном strtod()
в Linux . Стандарт C предусматривает только то, что underflow не может возвращать значение, превышающее наименьшее положительное значение double
, и errno
задано или нет значение, ERANGE
определенное реализацией 2 .
На самом деле существует обширная консультативная запись сертификата, которая рекомендует всегда устанавливать errno
значение 0 перед вызовом библиотеки и проверять его значение после вызова, чтобы указать, что произошла ошибка . Это связано с тем, что некоторые вызовы библиотеки будут установлены, errno
даже если сам вызов был успешным 3 .
При errno
запуске программы значение равно 0, но оно никогда не устанавливается равным 0 какой-либо библиотечной функцией. Значение errno
может быть установлено в ненулевое значение при вызове библиотечной функции независимо от того, есть ли ошибка, при условии, что ее использование errno
не описано в описании функции в Стандарте C. Для программы имеет смысл проверять содержимое errno
только после сообщения об ошибке. Точнее, errno
имеет смысл только после того, как библиотечная функция, которая устанавливает errno
ошибку, вернула код ошибки.
1. Ранее я утверждал, что это было во избежание маскировки ошибки от более раннего вызова. Я не могу найти никаких доказательств в поддержку этого утверждения. У меня также был фиктивный printf()
пример.
2. Спасибо @chux за указание на это. Ссылка C.11 §7.22.1.3 ¶10.
3. Указано @KeithThompson в комментарии.
errno
, вы всегда можете установить его на ноль самостоятельно.