Я должен установить errno?

Я пишу модуль, который экспортирует интерфейс, похожий на send и recv.

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

Должен ли я в такой ситуации установить errno, как это делает стандартная библиотека? Если да, то, поскольку errno зависит от потока, существует ли особый способ записи на нем, или я могу просто присвоить ему значение?

Изменить: экспериментируя, я заметил, что настройка errno по назначению работает. Тем не менее: это безопасно и портативно для любой системы?


person Dacav    schedule 25.03.2012    source источник
comment
Больше, чем вы когда-либо хотели узнать о errno и стандартах C, см. На странице stackoverflow.com/questions/12945486   -  person Nemo    schedule 02.11.2012


Ответы (6)


Это немного устарело, но в errno - в разделе 3 руководства говорится, что вы можете назначить его напрямую, даже если он это макрос, и он будет локальным потоком

person gbulmer    schedule 25.03.2012
comment
В этом нет ничего странного :-) Стандарт утверждает, что он расширяется до изменяемого lvalue. - person paxdiablo; 30.05.2014

Вы не только можете установить errno, во многих случаях вам следует установить errno. При вызове некоторых библиотечных функций вы можете надежно обнаружить ошибку, только если сначала установите errno в ноль. См. пример strtol.

Из спецификации POSIX strtol:

[CX] [Option Start] Функция strtol () не должна изменять установку errno в случае успеха.

Поскольку 0, {LONG_MIN} или {LLONG_MIN}, и {LONG_MAX} или {LLONG_MAX} возвращаются при ошибке и также являются допустимыми возвратами в случае успеха, приложение, желающее проверить наличие ошибочных ситуаций, должно установить errno на 0, а затем вызвать strtol () или strtoll (), затем проверьте errno. [Конец опции]

person Dan Moulding    schedule 05.07.2012

На самом деле, вы, вероятно, сможете выполнить «правильное» (как вы это выразились) управление ошибками, так как вы возвращаете int.

Просто используйте неотрицательные значения для количества прочитанных или записанных байтов и отрицательные значения для кодов ошибок. Вы не должны ограничивать себя -1:

enum myerrors {
    ERR_NO_MEMORY    = -1,
    ERR_BAD_ARGS     = -2,
    ERR_CPU_EXPLODED = -3,
    // and so on
};

Однако установка errno желаемым способом является допустимой. В стандарте указано, что errno расширяется до изменяемого lvalue, что означает, что вы можете установить его. От C1x/n1425, 7.5 Errors <errno.h>:

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

person paxdiablo    schedule 25.03.2012

Вы можете просто присвоить значение errno, но имейте в виду, что есть другие способы сообщить об ошибке, которые, в зависимости от вашей ситуации, могут быть более подходящими:

  1. Не возвращайте количество прочитанных байтов, а вместо этого используйте выходной параметр с типом int * (или size_t *, или как там вы используете). Затем вы можете вернуть код ошибки.
  2. Предполагая, что ваш возвращаемый тип является типом со знаком и отрицательное количество отправленных или полученных байтов не имеет смысла, используйте отрицательные значения, чтобы сигнализировать о соответствующих условиях ошибки.
person Julien Oster    schedule 25.03.2012
comment
errno используется почти всеми функциями в POSIX (кроме тех, которые возвращают код ошибки и несколько странных исключений), а не только низкоуровневые вещи. - person R.. GitHub STOP HELPING ICE; 25.03.2012

Да, вы можете назначить его, и да, назначение будет поточно-ориентированным. См. Является ли errno потокобезопасным?

person Kyle Jones    schedule 25.03.2012

От: http://support.sas.com/documentation/onlinedoc/sasc/doc700/html/lr1/errno.htm

Единственные переносимые значения для errno - это EDOM и ERANGE.

Так что это ответ на ваш вопрос о переносимости.

person prelic    schedule 25.03.2012
comment
Меня больше интересовали технические детали его назначения, но я не ожидал такой проблемы с переносимостью! :) - person Dacav; 25.03.2012
comment
@Dacav - я не думаю, что у вас есть какой-то особый способ установить его ... вы можете просто присвоить ему ... Я бы использовал значения перечисления, определенные в errno.h, если это возможно. - person prelic; 25.03.2012
comment
Этот список не совсем полный, EILSEQ требуется стандартом. - person paxdiablo; 25.03.2012
comment
@prelic Мой вопрос о настройке связан с тем, что это глобальная переменная, зависящая от потока, реализованная с помощью макросов. +1 для значений перечисления (что, конечно, строго необходимо, если вам нужны значимые значения!) - person Dacav; 25.03.2012
comment
@R .. По мере того, как я читаю больше, я вижу это ... не уверен, что эта статья устарела или просто неверна. - person prelic; 25.03.2012
comment
Что ж, POSIX - это отдельный стандарт от ISO C. Это правда, что ISO C не определяет много значений errno, но он определяет третий, EILSEQ. - person R.. GitHub STOP HELPING ICE; 25.03.2012