Почему ошибочно, когда функция POSIX показывает ошибку, возвращая -1 или NULL
При возникновении ошибки в одной из системных функций UNIX часто возвращается отрицательное значение и целое число
errno
устанавливается в значение, которое дает дополнительную информацию. - Расширенное программирование в среде UNIX, раздел 1.7
Это кажется странным:
- Он вводит связь между различными модулями компиляции стандартной библиотеки - состояния ошибок не определяются в вызывающих их модулях.
- Это вводит сложность реализации, потому что
errno
должен быть локальным потоком. - Это усложняет юзабилити, потому что пользователь должен проверить, что исходный системный вызов ошибочен, а затем проверить
errno
Который также является еще одним вызовом функции.
Почему бы не кодировать состояния ошибок в возвращаемых значениях?
2 ответа
В основном по историческим причинам.
Обратите внимание, что на самом деле, errno
сегодня не обычная глобальная переменная (так было в 1980-х годах). Это сегодня (C99, C11...) макрос - обычно расширенный до некоторого вызова функции, возможно __errno()
(и недавний стандарт C требует errno
чтобы быть макросом, см. n1570 §7.5); или это может быть расширено до некоторой локальной переменной потока, или даже до некоторой магии компилятора.
errno
хочет быть макросом для многопоточности, поэтому я думаю, что стандарты развивались, чтобы требовать, чтобы это был какой-то макрос
Так что вы должны #include <errno.h>
и использовать errno
макрос почти как если бы это была какая-то глобальная переменная, но зная, что на самом деле это не одна.
Детали зависят от реализации. Загляните внутрь исходного кода вашей стандартной библиотеки C, например, http://musl-libc.org/ имеет в errno / __ errno_location.c
int *__errno_location(void)
{
return &__pthread_self()->errno_val;
}
и в публичном заголовке include / errno.h:
int *__errno_location(void);
#define errno (*__errno_location())
и GNU libc имеет нечто очень похожее
Кстати, некоторые системные функции не возвращают целое число (например, mmap
), а некоторые функции POSIX не показывают ошибки через errno
например, dlopen
(увидеть dlerror
). Поэтому в каком-то стандарте было бы трудно гарантировать, что каждая ошибка может быть указана возвращаемыми значениями.
Я процитирую Линуса Торвальдса для этого.
"errno" - одна из тех немногих действительно дурных глупостей в UNIX. Linux исправил это, и не использует это внутренне, и никогда не будет. Жаль, что пользовательское пространство должно исправить правильный код ошибки, возвращаемый ядром, и превратить его в "ошибочную" глупость для обратной совместимости.
[...]
"errno" - одна из тех фундаментально сломанных вещей, которые не должны существовать. Это было неправильно в оригинальной UNIX, сейчас это неправильно.
[...]
Способ возврата отрицательных чисел ошибок в Linux намного приятнее. Он по своей сути потокобезопасен и не имеет никаких проблем с производительностью. Конечно, это зависит от наличия достаточного количества результирующего домена, чтобы вы всегда могли отделить возврат ошибок от хорошего возврата, но на практике это верно для всех системных вызовов.