Почему ошибочно, когда функция 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 намного приятнее. Он по своей сути потокобезопасен и не имеет никаких проблем с производительностью. Конечно, это зависит от наличия достаточного количества результирующего домена, чтобы вы всегда могли отделить возврат ошибок от хорошего возврата, но на практике это верно для всех системных вызовов.

Другие вопросы по тегам