LINUX.ORG.RU

Про обработку ошибок в C

 


0

1

Есть функция, которая аллоцирует память под объект, создает его и возвращает, а в случае ошибки возвращает NULL. А как бы вы вернули код ошибки, чтобы понять, где именно она произошла?

Так вроде лишний аргумент: void *create_object (..., int *error);

А можно ли (считается ли хорошим тоном) использовать errno со своими кодами ошибок?

В твоем конкетно взятом случае ENOMEM в errno запишет сама функция выделения памяти. Твоя задача - не запороть это значение.

anonymous ()

Смотря какой тип и диапазон возвращаемого значения. Можно вернуть -1, 0, сам код ошибки, минус сам код ошибки, NULL, специальный указатель на ошибочный синглтон (или просто уникальный адрес, обозначающий ошибку). Если нельзя код вернуть прямо в результате, создал бы my_module_errno и my_module_strerror (хотя это скорее онанизм, чем рил-ворлд-кодинг).

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

Удваиваю анонимуса про сохранение оригинального errno кстати. Так или иначе большинство фейлов происходит именно в системных вызовах.

arturpub ★★ ()
Ответ на: комментарий от anonymous

Functions should return int and negative errors instead of NULL - Return NULL in malloc() is fine, return NULL in fopen() is not! - Pass allocated objects as parameter (yes, ctx_t** is OK!) - Returning kernel style negative <errno.h> error codes is cool in userspace too. Do it!

anonymous ()
Ответ на: комментарий от anonymous

Причём тут выделение памяти? Функция создает объект, выделение памяти под него - десятая задача. Представь, что она сделала структуру и заполняет её поля, причём при этом может появиться ошибка.

lispfuerimmer ()
Ответ на: комментарий от lispfuerimmer

Весь гном-стек кстати при g_assert*, g_return_if_fail и т.п. пишет событие в stderr и возвращает NULL/0/whatever. И при отладке очень удобно, и прога не валится в рантайме — просто отвалилась функция какая-то и черт с ней.

Так что вполне нормальный способ. Подумай: кто будет разбираться с ошибкой, как он ее будет решать, и что должна сделать недебильная программа при ее возникновении — и все встанет на свои места.

arturpub ★★ ()
Ответ на: комментарий от lispfuerimmer

Я не хочу, чтобы моя библиотека печатала всякий мусор.

o_O

Хозяин барин. Тогда создай табличку в документации к либе в которой у каждой функции свои номерки возврата ошибок.

Смотрим код ошибки и ага это функция такая-то. Ползём в код править.

Но я бы всё же включил printf(); подробные логи важны, скорость это не убавит, а в случае стопора либы сразу будет видно что с ней произошло.

Dron ★★★★★ ()
Ответ на: комментарий от arturpub

Весь гном-стек кстати при g_assert*, g_return_if_fail и т.п. пишет событие в stderr и возвращает NULL/0/whatever.

Точно, сделаю свой макрос REPORT_ERROR с возможностью отключения. Это будет оке, так как стратегий исправления ошибки в программе не предвидится. (Я делаю чтение/запись сложно организованных данных на диск).

lispfuerimmer ()
Ответ на: комментарий от lispfuerimmer

Гм, слово stderr как бы намекает, что это поток для... чего? Можешь валить туда всю диагностику, а включать/выключать ее по ./myprog -v или -vv, и my_module_set_debug_level(3).

arturpub ★★ ()

А можно ли (считается ли хорошим тоном) использовать errno со своими кодами ошибок?

Нет, определенно не считается. Если очень хочется отдавать коды ошибок в духе errno, можешь посмотреть на поведение http://wiki.libsdl.org/SDL_GetError .

Manhunt ★★★★★ ()
Последнее исправление: Manhunt (всего исправлений: 1)

Я макросы для этого использую, которые в stderr плюются (название функции, номер строки, имя файла, опциональный текст).

Anon ()

errno можно в своих целях использовать только если стопроцентно между установлением errno и проверкой нет никаких стандартных функций. А это маловероятно.

Anon ()
Ответ на: комментарий от anonymous

Анонимус верно указал, что лучше возвращать не указатель на выделенный объект, а код ошибки. Указатель можно вернуть через параметр функции.

Sorcerer ★★★★★ ()

Как вариант - в случае ошибки кидать зигу эксепшен.

RiseOfDeath ★★★★ ()
Ответ на: комментарий от lispfuerimmer

Представь, что она сделала структуру и заполняет её поля, причём при этом может появиться ошибка.

В этом случае структуру удалить и вернуть NULL. Объект-то все равно использовать нельзя

abalakin ★★ ()
Ответ на: комментарий от Dron

Я не хочу, чтобы моя библиотека печатала всякий мусор.

Полностью согласен

Многие библиотеки (GSL, GTK и др.) создает функцию, возвращающую код ошибки, если она произошла. Например

int mylib_get_error_code();
При этом отсутствие ошибок хорошо бы обозначать 0 (проще проверять).

Но я бы всё же включил printf(); подробные логи важны, скорость это не убавит, а в случае стопора либы сразу будет видно что с ней произошло.

Никто не мешает возвращать строку с подробным описанием ошибки по запросу

const char *mylib_get_error_message();

abalakin ★★ ()
#define ERRMSG(aa, bb) static const char aa []={ bb } __attribute__ ((section ("errormsgs")));

extern char errormsgs_start;
extern char errormsgs_stop;

inline int is_error(void * p){
   return (p>=&errormsgs_start && p<&errormsgs_stop);
}

и гугли linker script - тебе надо будет взять скрипт дефолтный и вписать туда в секцию errormsgs два символа в начале errormsgs_start и в конце errormsgs_stop

ckotinko ☆☆☆ ()

Код ошибки передавать на стеке (читай-возвращать), заодно выставляя обобщенную причину в errno. Там достаточный ассортимент:)

Если по логике и юзе-кейс удобно чтобы функция возвращала обьект , то пусть лучше будет аргумент void ( *onerror)(...), чем int *error; при вложенных вызовах так юзер сможет детальнее разобраться что и где поломалось;

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