Определяемые пользователем значения диапазона errno (POSIX или Linux)

Вопросы для POSIX, если это возможно, иначе для платформ, специфичных для Linux:

  1. Есть ли пользовательский errno ценности? (что касается сигналов SIGUSR1 а также SIGUSR2)
  2. Как найти errno значение не используется системой? (отрицательные значения?)
  3. Как предотвратить strerror() перерыв? (проверьте перед errnum знак?)

Мой код open() ресурс и уведомляет другой объект. Уведомление Event передает систему errno если происходит сбой (ноль при успехе).

Но ошибки также могут быть обнаружены в моем коде, например, if(count>=size), И я хочу повторно использовать поле Event::errnum передать эту неудачу. Поэтому мой определяемый пользователем код ошибки не должен перекрывать системный errno ценности.

я нашел errno диапазон 9000–11000 зарезервирован для пользователя, но это, похоже, характерно для средства обработки транзакций...

Обратите внимание, что мой вопрос не о том, что определено в библиотеке. struct Event не выставляется вне моего кода. Мой код не перезаписывается errno,

Ниже приведен фрагмент кода на C++, но мой вопрос также относится к c.

#include <cerrno>

#define E_MY_USER_DEFINED_ERROR 9999

struct Event
{
    int fd;
    int errnum;
};

struct Foo
{
    Foo( int sz ) : count(0), size(sz) {}

    Event open( const char name[] )
    {
        if( count >= size )
            return { -1, E_MY_USER_DEFINED_ERROR };

        int fd = 1; // TODO: open ressource...
        if (fd < 0) return { -1, errno };
        else        return { fd, 0 };
    }

    int count, size;
};

int main()
{
    Foo bar(0);
    Event e = bar.open("my-ressource");
    // send Event to another object...
}

2 ответа

Решение

Настоящий errno значения не определены стандартами C и C++. Таким образом, нет способа вернуть определенное (положительное) целое число и гарантировать, что оно не будет конфликтовать с тем, которое использует реализация. Стандарт C требует только три марко:

C11 осадка, 7,5 ошибок

Макросы

EDOM
EILSEQ
ERANGE

которые расширяются до целочисленных константных выражений с типом int, различными положительными значениями и которые подходят для использования в директивах предварительной обработки #if;

Так что вы не знаете, что другое errno значения определены в вашей реализации.

errno значения являются положительными целыми числами в стандарте C и POSIX. Таким образом, вы можете использовать свое собственное перечисление с отрицательными значениями, чтобы определить свои собственные числа ошибок. Но тогда вы не можете использовать интерфейсы strerror/perror. Поэтому вам может понадобиться дополнительная оболочка для strerror/perror для интерпретации ваших собственных номеров ошибок.

Что-то вроде:

enum myErrors{
ERR1 = -1,
ERR2 = -2,
...
ERR64 = -64
};

char *my_strerror(int e)
{
   if (e>=ERR1 && e<=ERR2)
      return decode_myerror(e); // decode_myerror can have a map for  
                                //your error numbers and return string representing 'e'.
   else
      return strerror(e);
}

и аналогичный для perror,

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

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

В ответе Blue Moon предлагается использовать отрицательное значение в качестве пользовательского диапазона. Это идеально в моем случае.

Ниже приведен фрагмент моего вопроса с использованием его предложения. Этот фрагмент также доступен на coliru.

#include <cerrno>
#include <cstring>
#include <iostream>

#define E_MY_USER_DEFINED_ERROR -1

struct Event
{
    int fd;
    int errnum;
};

struct Foo
{
    Foo( int sz ) : count(0), size(sz) {}

    Event open( const char name[] )
    {
        if( count >= size )
            return { -1, E_MY_USER_DEFINED_ERROR };

        int fd = std::strlen(name); // TODO: open ressource...
        if (fd < 0) return { -1, errno };
        else        return { fd, 0 };
    }

    int count, size;
};

int main()
{
    Foo bar(0);
    Event e = bar.open("my-ressource");
    std::cout << std::strerror( e.errnum ) << std::endl;
}

Вывод с использованием GCC

Unknown error -1

Вывод с использованием Clang

Unknown error -1
Другие вопросы по тегам