Безопасно ли считать, что errno всегда положителен?

Я пишу программу, в которой большинство используемых библиотечных функций возвращают -1 при ошибке и устанавливают errno. Поведение программы таково, что она завершает работу в случае возникновения ошибки. Чтобы определить точную точку выхода и ошибку извне программы (пример с использованием gdb), я хочу использовать следующий метод:

err = func_1(..arglist_1..);
if(err != 0)
{
    perror("func(..arglist..)");
    return ((1u << 8) | errno);
}
//..
//.. some more funcs
//..
err = func_n(..arglist_n..);
if(err != 0)
{
    perror("func(..arglist_n..)");
    return (((unsigned)n << 8) | errno);
}

Проблема здесь в безопасных предположениях.

Реальность: errno объявляется как extern int errno; внутри errno.h
Предположение 1: значение errno всегда меньше 255.
Предположение 2: ошибка нет всегда положительна.

На основе всех констант ошибок (EAGAIN и т. д.), определенных в errno.h, эти предположения в настоящее время верны. Можно ли предположить, что они верны и в будущем?

P.S.: Я не хочу зависеть от perror() для определения точки выхода.


person Don't You Worry Child    schedule 21.08.2013    source источник
comment
Я сомневаюсь, что любое предположение безопасно. Что касается второго, вы считаете 0 положительным?   -  person jxh    schedule 21.08.2013
comment
0 не исключено, так как здесь указано: No function in this volume of IEEE Std 1003.1-2001 shall set errno to 0.   -  person Don't You Worry Child    schedule 21.08.2013
comment
Тот факт, что ни одна функция в стандартной библиотеке не устанавливает для него значение 0, не означает, что кто-то другой не устанавливает для него значение 0. Для некоторых стандартных библиотечных функций единственный способ определить, не удалось ли выполнить вызов, — сначала установить errno в 0, а затем посмотреть, что делает функция.   -  person jxh    schedule 21.08.2013
comment
@jxh: вы правы, ответ Джонатана Леффлера объяснил мне все. И да, я где-то изучал такие функции, которые возвращают -1 в случае успеха и могут быть проверены на наличие ошибок, только установив errno в 0.   -  person Don't You Worry Child    schedule 21.08.2013
comment
@jxh: Эврика!! нашел!! примером таких функций является getpriority() :-).   -  person Don't You Worry Child    schedule 21.08.2013
comment
Хорошо поймал! Кроме того, вы, вероятно, уже знаете, что стандартная библиотека может установить errno даже при успешном вызове.   -  person jxh    schedule 21.08.2013
comment
@jxh: Извините, но я не понял. Почему errno должен быть установлен на успех? Я думаю, что для вышеупомянутой функции errno останется прежним при успехе и будет установлен только при какой-либо ошибке. Однако в обоих случаях функция вернет -1.   -  person Don't You Worry Child    schedule 21.08.2013
comment
справочная страница errno прямо говорит, что это может произойти в последнем предложении первого абзаца. Проблема в том, что библиотечная функция может вызывать другие функции, которые устанавливают errno в случае ошибки, но не влияют на успех библиотечной функции. Например, библиотечная функция может проверить наличие одного из двух файлов, если любой из них существует, вызов может продолжиться и завершиться успешно, даже если первый проверяемый файл не существует.   -  person jxh    schedule 21.08.2013
comment
@jxh спасибо, понял!!   -  person Don't You Worry Child    schedule 21.08.2013


Ответы (1)


Статус выхода вашей программы ограничен значениями 0..255, поэтому, если эти операторы возврата исходят из программы main(), старшие биты значения не имеют.

Стандарт C (ISO/IEC 9899:2011 §7.5 Ошибки <errno.h>) гласит:

errno
, которое расширяется до изменяемого значения lvalue201), которое имеет тип int и продолжительность локального хранения потока, значение которого устанавливается в положительное число ошибок несколькими библиотечными функциями.

201) Макрос errno не обязательно должен быть идентификатором объекта. Он может расширяться до изменяемого lvalue, полученного в результате вызова функции (например, *errno()).

Стандарт C предполагает, что ошибки должны быть положительными. POSIX (IEEE Std 1003.1, издание 2013 г.) указывает для <errno.h>:

Заголовок <errno.h> должен определять следующие макросы, которые должны расширяться до целочисленных константных выражений с типом int, отдельными положительными значениями (за исключением случаев, указанных ниже), и которые должны подходить для использования в директивах предварительной обработки #if: ...

Таким образом, вы можете с уверенностью предположить, что (сгенерированные системой) номера ошибок положительны, но ваш код может установить errno отрицательным (или нулем). На данный момент ни одна система POSIX не генерирует число ошибок больше, чем где-то ниже 200, поэтому предположение, что они будут ограничены 255, безопасно в краткосрочной перспективе, но, вероятно, не в долгосрочной. Нет причин, по которым они должны быть такими ограниченными.

Ваша заявленная «реальность» применима только к программам без потоков. Если вы компилируете для поддержки многопоточности, то errno не просто объявляется как extern int errno;, и ни при каких обстоятельствах вы не должны пытаться объявлять errno для себя. Единственный безопасный способ объявить это через заголовок <errno.h>.

person Jonathan Leffler    schedule 21.08.2013
comment
Хорошо, я получил ответ, спасибо, Джонатан Леффлер. Во-первых, он прав, я собирался сделать это в main(). Далее моя ошибка, я забыл про многопоточные программы. Также я использовал старую копию стандарта для справки, там это не упомянул, что он всегда будет положительным. - person Don't You Worry Child; 21.08.2013
comment
C89 не оговаривал, что номера ошибок должны быть положительными (только ненулевыми); C99 действительно оговаривал, что номера ошибок должны быть положительными. Интересно, что в POSIX 1997 говорится, что заголовок <errno.h> предоставляет объявление для errno и дает ненулевые значения для следующих символических констант. что соответствует действующему на тот момент стандарту C89 (C90). - person Jonathan Leffler; 21.08.2013
comment
@nishant: интересно — вы ссылаетесь на страницу POSIX 2004 для errno, на которой не упоминается «положительный» (как и на странице POSIX 2013 для errno), тогда как я ссылался на страницу POSIX (2013) для <errno.h>, где это упоминается (как и страница POSIX 2004 для заголовка) . Думаю, мне повезло, что я выбрал правильное место для поиска; Я не знал об асимметрии. - person Jonathan Leffler; 21.08.2013