metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2012-04-21 09:12 pm

Чистый C, обработка ошибок

Это, а как в C принято обрабатывать ошибки?
Т.е. обычная программа: я открываю всякие ком-порты, сокеты и файлы, что-то с ними пытаюсь делать, затем закрываю. В дельфи/java/C#/Clojure это всегда делается через обработку исключений в виде try-finally/using или чего-то аналогичного, в C++ - RAII, а вот что делать в С? Аналогично, с выводом сообщений об ошибке - try{..}catch(Exception e) {logger.Fatal(e};raise}

Я каждую вызываемую функцию проверяю на адекватность возвращаемого результата и при ошибке вывожу в stderr сообщение и strerror(errno), причем выглядит это достаточно единообразно, чтобы хотелось автоматизировать, но принято ли делать хитрожопые макросы типа CHECKERROR(some_call(),"some_call failed") и из них вываливаться из программы при ошибках?

А, и это - принято ли в C заниматься конкатенацией строк по поводу и без повода? А то, скажем, я привык в простых программах особо не мудрить и при необходимости складывать строки, если нет явных требований к производительности. Например, какая-нибудь дурь типа генерации строковых команд из шаблонов и параметров - тупо поскладывал строки и вернул результат. А в С придется strcat использовать, буфера какие-то объявлять, память выделять, трястись за ее удаление или же писать результат прямо в выходной файл, что вообще tight coupling.

[identity profile] metaclass.livejournal.com 2012-04-22 07:10 am (UTC)(link)
О, apr кстати, полезен.

[identity profile] metaclass.livejournal.com 2012-04-22 07:11 am (UTC)(link)
Себе, себе пишу. Для кого-то я не настолько хорошо С умею.

[identity profile] sleepy-drago.livejournal.com 2012-04-22 07:20 am (UTC)(link)
omfg. Ну тогда регионы памяти + списки ресурсов функции (а-ля atexit) во все поля. Макрос проверки хорош тем что убирает if-return и оставляет линейность кода что хорошо для чтения.

[identity profile] justy-tylor.livejournal.com 2012-04-22 08:47 am (UTC)(link)
Для серверов/десктопов ок. Но на других платформах бывают проблемы с поддержкой исключений, что вынуждает использовать хитрые макросы и в сишном, и в плюсовом коде. Телефоны, телевизоры, Xbox 360...

[identity profile] dair-spb.livejournal.com 2012-04-22 08:55 am (UTC)(link)
Я чувствую личное ;-)

[identity profile] dair-spb.livejournal.com 2012-04-22 09:03 am (UTC)(link)
Я, в результате подобных же мозговых нестыковок, дошёл до такого:

 b r

     res  allocSomething2
     res  
    
        
        cres
        releaseSomething2
    


 a

     res  allocSomething1
     res  
    
        
        bres
        releaseSomething1
    

Edited 2012-04-22 09:03 (UTC)

[identity profile] metaclass.livejournal.com 2012-04-22 09:08 am (UTC)(link)
Я на работе жэстачайшым образом насаждаю процессы, баг-трекеры, меркуриалы и прочий ад заборов и коровников :)

[identity profile] berezovsky.livejournal.com 2012-04-22 09:08 am (UTC)(link)
ээээ, как разукрашечку сделать?

[identity profile] esil0x.livejournal.com 2012-04-22 09:14 am (UTC)(link)
Так RAII прекрасно работает и без исключений. Все выделенные ресурсы будут подчищаться перед return, независимо от того, где return сделать.

[identity profile] justy-tylor.livejournal.com 2012-04-22 09:40 am (UTC)(link)
RAII работает для ресурсов, но не для control flow. Для кода f(); g(); возникновение исключения внутри f() должно отменить выполнение g(), и далее по стеку. Вызовы всёх функций-с-исключениями придётся обернуть в макросы.

[identity profile] esil0x.livejournal.com 2012-04-22 09:42 am (UTC)(link)
Ну в отсутствии исключений обычно используют коды возврата. Проверил код возврата f() и вернул управление, если код плохой.

[identity profile] dair-spb.livejournal.com 2012-04-22 09:48 am (UTC)(link)
Первая ссылка в гугле по запросу "c code colorizer"

[identity profile] justy-tylor.livejournal.com 2012-04-22 09:55 am (UTC)(link)
Вот чтобы не захламлять исходники сотнями if (problem) return dummy; приличные люди и используют макросы.

[identity profile] esil0x.livejournal.com 2012-04-22 09:59 am (UTC)(link)
Так это дело вкуса и ортогонально проблеме очистки ресурсов.

[identity profile] blackyblack.livejournal.com 2012-04-22 10:13 am (UTC)(link)
C++ так-то ничем не лучше Си. Исключения - тот же гото, только в профиль. :) А первый пункт правильно написан - я как раз его выше предложил.

[identity profile] justy-tylor.livejournal.com 2012-04-22 10:21 am (UTC)(link)
Лол.

[identity profile] esil0x.livejournal.com 2012-04-22 10:23 am (UTC)(link)
Ага.

[identity profile] theiced.livejournal.com 2012-04-22 11:22 am (UTC)(link)
да конечно. кусок говна получается с гарантией. способ рабочий, инфа 100%.

[identity profile] fkng-stupid-lj.livejournal.com 2012-04-22 11:29 am (UTC)(link)
foo_t* 
foo(void)
{
    bar_t *bar;
    baz_t *baz;
    foo_t *foo;

    bar = bar_new();
    if (!bar)
      goto e0;
    baz = baz_new();
    if (!baz)
      goto e1;
    foo = foo_new(bar, baz);
    if (!foo)
      goto e2;
    return foo;

e2: baz_free(baz);
e1: bar_free(bar);
e0: return NULL;
}


Дешево и сердито. Плюс вариации. Можно, конечно, и exceptions замутить (типа таких (http://www.on-time.com/ddj0011.htm)), но в сборном проекте они не особенно полезны, вот если монолитная система, тогда может быть.

Насчет строк -- или, как сказали, aprintf, если есть, или поискать какую-нибудь более развесистую библиотеку.

[identity profile] esil0x.livejournal.com 2012-04-22 11:37 am (UTC)(link)
Да хоть кусок торфа - всем похер, ибо работает.

[identity profile] fkng-stupid-lj.livejournal.com 2012-04-22 11:37 am (UTC)(link)
Имхо, проверки лишние в конце. Вполне можно писать код так, чтобы goto переходил точно к нужной команде освобождения. Меткам название придумывать, конечно, скучно, я их просто нумерую -- e0, e1, e2, и т. д.

[identity profile] sbj-ss.livejournal.com 2012-04-22 12:33 pm (UTC)(link)
Повторюсь - возможна ситуация, когда не все ресурсы захвачены, но это не ошибка. Ну не указан какой-то опциональный атрибут у узла. В таких случаях приходится проверять.

[identity profile] fkng-stupid-lj.livejournal.com 2012-04-22 02:22 pm (UTC)(link)
Такие случаи, имхо, логичнее проверять непосредственно у метки:

e2: if (bar) free_bar(bar); /* то ли выделен, то ли нет */
e1: free_baz(baz); /* заведомо выделен к этому моменту */
e0: return NULL;

[identity profile] sbj-ss.livejournal.com 2012-04-22 02:23 pm (UTC)(link)
Да, хороший вариант.

[identity profile] fillest.livejournal.com 2012-04-22 02:39 pm (UTC)(link)
по поводу строк - http://bstring.sourceforge.net/

Page 5 of 6