Зачем возвращать отрицательный номер ошибки? (например, возврат -EIO) - PullRequest
25 голосов
/ 04 декабря 2009

Еще один простой пример:

if (wpa_s->mlme.ssid_len == 0)
    return -EINVAL;

Почему унарный минус? Это (обычно) делается для функций, которые возвращают> 0 в случае успеха и <(=) 0 в случае неудачи или есть какая-то другая причина? </p>

Ответы [ 4 ]

17 голосов
/ 04 декабря 2009

Во-первых, это на самом деле не вещь Си. Вы смотрите на функцию, которая написана на C для какой-то цели. Те же самые соглашения могут использоваться на любом языке.

В старые времена Unix существовало соглашение, согласно которому 0 означало успех, положительное число означало незначительные проблемы, а отрицательное число означало какой-то сбой. Таким образом, было также своего рода соглашение if (foo() >= 0) { /* success of a sort */ }.

Это, несомненно, было связано с кодами возврата процесса Unix, где 0 был успешным.

14 голосов
/ 04 декабря 2009

Это в основном причины. Многие функции имеют много «хороших» положительных результатов, поэтому для кодов ошибок остаются отрицательные значения.

Коды ошибок C / POSIX немного «исторически выросли», поэтому нет смысла пытаться приписать им слишком много рифмы или причины.

Многие современные языки генерируют исключения для ошибок, чтобы им не приходилось перехватывать часть возможного диапазона ответов для кодов ошибок. Конечно, в любом случае есть компромиссы.

7 голосов
/ 04 декабря 2009

Ваше понимание в целом верно. Очевидная интерпретация - правильная.

Однако стандартное соглашение немного отличается от вашей формулы.

В Unix, программа, которая завершается с 0 тестами состояния как true или success для утилит уровня CLI, таких как оболочка. В библиотеке -1 обычно возвращает ошибку.

Это приводит к общей парадигме, где >= 0 означает хорошо , а < 0 означает ошибка. Ничто из этого не изложено в камне.

Кстати, это может быть классифицировано как паттерн дозорного , и вы можете назвать его возвращением дозорного. Это на самом деле комбинация сторожевого "значения" и кода ошибки, и его легче набирать и легче сделать потокобезопасным, чем возвращать код ошибки в одном месте и значение часового для ошибки в другом.

Википедия сообщает, что значение Sentinel используется для завершения цикла, но я думаю, что возврат функции будет гораздо более распространенным случаем. Никто точно не отвечает за эти определения.

1 голос
/ 04 января 2018

С точки зрения оптимизации, использование отрицательных чисел позволяет ядрам на основе Unix проверять код ошибки, используя только одно сравнение вместо двух.

Функции в ядре часто возвращают коды ошибок вместо указателей. Это означает, что коды ошибок не могут перекрываться с действительными адресами указателя, поэтому в основном они должны иметь либо самые низкие значения без знака (>= 0), либо самые высокие значения (<= unsigned max).

Проверка значений указателей для NULL и для кодов ошибок является очень распространенной операцией, поэтому имеет смысл оптимизировать их.

Обычно нижние значения < 0x8000 равны NULL, а верхние значения - коды ошибок (помните, что -1 сохраняется как 0xff...ff, максимально возможное значение без знака).

Это означает, что вы можете использовать одно сравнение для проверки:

NULL, если x <= 0x8000 (верно для 0 до 0x8000)

ERRNO, если x >= (unsigned long)(-MAX_ERRNO) (истина от -1 до -MAX_ERRNO)

Вы можете увидеть это в файле err.h Linux.

...