LINUX.ORG.RU

Обработка ошибок в библиотеке на C


0

3

Есть библиотека на plain C, которая работает с неким форматом файлов. Интерфейс простой:

typedef struct mylib {
  int mylib_errno;
  ...
} *mylib_t;

mylib_t lib = mylib_open("filename", ...);
somecount = mylib_getsomecount(lib, ...);
if (somecount < 0)
  errx(1, "cannot get some count: %s\n", mylib_strerror(mylib_getlasterror(lib)));

mylib_close(lib);

Т.е. в struct mylib хранится errno в котором могут быть как положительные значения (от системных вызовов и функций из libc) так и отрицательные от самой библиотеки.

Это отлично работает, но только когда в mylib_open ничего сложного не делается (тогда если возвращается NULL, это однозначно malloc вернул ENOMEM) и когда в качестве someval можно передать невозможное значение (ну это не особо проблема, потому что если нельзя, то можно передавать через указатель на манер stat(2)). Но вот нужно в mylib_open сделать что-то нетривиальное, и потом узнать что случилось. Вопрос: как лучше построить интерфейс в общем случае?

Вариант 1:

typedef int mylib_code_t;

mylib_code_t mylib_open(mylib_t *);
mylib_code_t mylib_getsomeval(mylib_t, int *)

Т.е. выходные данные всегда передавать через указатели, а возвращать всегда код ошибки (или MYLIB_OK). Это не нравится по той причине, что так пользователю вероятнее забыть что-то освободить, т.е. вызвать mylib_open(&lib) при уже открытом lib уже открыт. Все-таки с lib = mylib_open() это легче заметить. Далее, нельзя написать в одну строку struct mylib *lib = mylib_open() и общее несогласование интерфейса с обычными библиотечными функциями, которые возвращают данные а не коды.

Вариант 2:

Хранить свой глобальный errno. Описанных выше проблем нет, но имеем проблемы с многопоточными программами. С другой стороны, если есть портабельный способ так объявить mylib_errno, чтобы при сборке с потоками он был в TLS, а без потоков просто глобальным, ИМХО это было бы самое оно.

Вариант 3:

Никогда не делать в open ничего сложного. Если нужно, добавить отдельную функцию, к вызову которой хэндл библиотеки уже будет выделен и будет куда сохранить ошибку. Лишняя строчка при инициализции, и по-моему, это единственный минус. Не так красиво, как вариант 2.

Идеи? Особенно интересует второй вариант. Есть мысли про установку обработчика ошибки + setjmp, но а коде который это использует невозможно разбираться, да и jmpbuf надо передавать опять таки. Т.е. это ухудшенный вариант 1.

★★★★★

Ответ на: комментарий от nanoo_linux

Это мой оригинальный вариант. Отсутствие возможности узнать почему open провалился неприемлимо.

slovazap ★★★★★
() автор топика
Ответ на: комментарий от nanoo_linux

Что еще за интовый дескриптор? А вообще, я уже написал чем мне этот вариант не нравится.

slovazap ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.