Бібліотека С не встановлена 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 лише передбачає, що під потоком не може повернутись значення, що перевищує найменший позитивний показник double
, і встановлено, чи не errno
визначено ERANGE
реалізацією 2 .
Насправді існує обширний довідковий запис cert, який рекомендує завжди встановлювати 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
, ви завжди можете встановити його на нуль.