Библиотека 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, вы всегда можете установить его на ноль самостоятельно.