LINUX.ORG.RU

[C] [жизнь без исключений] Как вы обрабатываете ошибки?

 


0

0

Пишу на C прошивку для микроконтроллера. Возникла следующая проблема:

while (1) {
	..
	for (..) {
		..
		if (..) {
			вдруг неожиданно произошло что-то очень не хорошее, например, аппаратная ошибка несовместимая с нормальной работой программы, нужно выйти из цикла while (1)
		}
		..
	}
	..
	switch (..) {
	case ..:
		if (..) такая же ситуация...
		break;
		..
	}
	..
}
.. 
if (флаг если ошибка) {
	обработка
}
..

И как тут быть? Неужели goto, и будет мне вагон счастья? А как же «напишешь «goto» и за тобой придёт бабай! Буууу!» (c), Дейкстра и весь такой прочий антураж?


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

6 гото - вот это [сеnsored].. а количество точек возврата код не портит, если тебе так не нравиться идеология Си, то прогай на паскале.

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

>потому что ты не смог её переписать без использования goto и кучи копипасты?

смог - нет ниодной копипасты и goto :)

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

Мне не нравится количество копипасты в твоём коде. Ты 6 раз пишешь одно и то же в разных местах -- не настораживает?

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

Специально для сильновидящих копипаста выделена символом '>' в начале строки.

int create_socket(const char *path, unsigned int perm, unsigned int nrlisten)
{
        struct sockaddr_un sockaddr;
        int err, fd;

        if((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
             return -1;

        if(fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
        {
>           close(fd);
           return -1;
        }

        sockaddr.sun_family = AF_UNIX;
        strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);

        if(bind(fd, (struct sockaddr *)&sockaddr, SUN_LEN(&sockaddr)) < 0)
        {
>           close(fd);
           return -1;
        }

        if(chmod(path, perm) < 0)
        {
>           unlink(path);
>           close(fd);
           return -1;
        }

        if(listen(fd, nrlisten) < 0)
        {
>           unlink(path);
>           close(fd);
           return -1;
        }

        //тут был код автора который к Си отношения не имел.
        return fd;

}

И ещё два места, где ты опять будешь копипастить, ты ничтоже сумнящеся выкинул.

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

>//тут был код автора который к Си отношения не имел.

Если непонятно, то ОК, пусть на фоне будет абстракция:

int check1() {
  return 1;
}

int check2() {
  return 1;
}

void check_fail() {
  perror( "fail\n" );
}

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

Копипаста это хотябы кусок какойто логики, ты ещё многократное использование какого либо оператора копипастой назови, детский сад:)

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

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

> Ты 6 раз пишешь goto, не настораживает? Ты просто пишешь goto, не настораживает?

Что должно настораживать? Что код прекрасно читаем? Что освобождение ресурсов выполняется строго в одном месте? Что вероятность при дальнейшем изменении кода забыть выполнить какое-нибудь необходимое действие -- минимальна?

Что именно?

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

> Копипаста это хотябы кусок какойто логики, ты ещё многократное использование какого либо оператора копипастой назови, детский сад:)

С какого количества выражений начинается "кусок какой-то логики"? close(fd) в случае ошибки, если он был открыт -- не логика? 'unlink(path);close(fd);' -- не логика?

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

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

Ну спроектируй эту функцию, где не нужен был бы ни goto, ни груда копипасты. Что она делает -- очевидно даже детсадовцу, так что вперёд.

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

>Что код прекрасно читаем?

код с goto в принципе не может быть читаем, я привёл вариант той функции в читаемом виде.

>Что вероятность при дальнейшем изменении кода забыть выполнить какое-нибудь необходимое действие -- минимальна?

у тебе огромна вероятность просто запутать обработку ошибок своими метками.

>Что освобождение ресурсов выполняется строго в одном месте?

у меня тоже в одном месте, если ты не заметил - перечитай ещё раз.

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

> 6 гото - вот это [сеnsored].. а количество точек возврата код не портит, если тебе так не нравиться идеология Си,

так значит дело не в красоте и читабельности, а как я первоначально и сказал в религии и идеологии ?

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

я уже написал выше, ты читать не умеешь? страница 2 вроде.

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

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

> код с goto в принципе не может быть читаем, я привёл вариант той функции в читаемом виде.

Это нагромождение копипасты -- читаемо?! OMFG...

> у тебе огромна вероятность просто запутать обработку ошибок своими метками.

С чего это вдруг?

> у меня тоже в одном месте, если ты не заметил - перечитай ещё раз.

Смотри на свой код до просветления. 4 раза зовём close(fd), 2 раза unlink(path). А на самом деле 6 раз close(fd), 4 -- unlink(path), 2 -- check_fail(), который ты выкинул.

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

идеологию я упомянул в том ключе, что в Си предусмотрено и поощеряется использование многих точек выхода, а в паскале нет.

а читабельность с goto, не смеши - я уже вдоволь насмеялся:))

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

> я уже написал выше, ты читать не умеешь? страница 2 вроде.

Читать не умеешь тут только ты. Думать тоже. Я сказал -- без груды копипасты.

> проектировать нужно не одну функцию, а хотябы логический блок.

Тебе объяснить, что эта функция делает? Тебе явно это непонятно.

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

>Смотри на свой код до просветления.

Я писал там как сделать, чтобы этого небыло. Троль, хорошщь читать только то что тебе нужно:) И ещё кое что писал чуть выше, про проектирования - а то даёте мне одну функцию оторваную от всего, и та явно криво написана.

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

Читабельность это когда код прозрачен и влазит на экран. В случае с goto предпосылки для этого есть, так как освобождение ресурсов делается один раз в одном месте в конце функции. При правке кода, в случае добавлении/удалении новых кусков в функцию, ошибиться при подходе с goto сложнее.

А религию с идиологией и ссылки на авторитетов можешь запихнуть в задницу, своей головой думать надо.

Reset ★★★★★
()

<offtop>хоть все и не любят С++ - но задача освобождения ресурсов там решается элементарно и читабельно</offtop>

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

>Тебе объяснить, что эта функция делает? Тебе явно это непонятно.

мне явно понятно:)

Короче я так понял ты программа для тебя это две функции на 100 строк? :)) Когда напишешь, чтонить более менее, тогда и поговорим.

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

На печеньку:

Мне нужно открывать в 5 местах слушающий unix domain socket. Потом, предположим, читать оттуда строку, что-то с ней делать (во всех 5 местах -- разное), и писать обратно. Проектируй.

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

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

>ошибиться при подходе с goto сложнее.

ААААААА!!!! ЖЕСТЬ!:)))

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

> <offtop>хоть все и не любят С++ - но задача освобождения ресурсов там решается элементарно и читабельно</offtop>

Вот если бы в нём других проблем не было, сказка был бы, а не язык. 8))

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

>Выше я привёл функцию из драйвера контроллера pci под линукс
это 3.14-ец еще и к ядру цепляется?
megaErrno - предчувствую мегаизврат.

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

Нелепые прыжки это лапша в стиле древнего фортрана. Ты еще скажи, что switch или набор if'ов это нелепые прыжки. А сам вызов функции какой прыжок.

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

> close(fd);
> return -1;

...
> close(fd);

> return -1;

...
> unlink(path);

> close(fd);

> return -1;

...
> unlink(path);

> close(fd);

> return -1;

нереальная пое#%нь.
а теперь представь себе, что тебе надо добавить еще один unlink или close или что-то в этом духе.

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

>так намного лучше чем каша с goto.
да нету там никакой каши с goto. что ты чушь-то несешь?
каша с goto была в примерах в книжах "basic для чайников" середины 80-ых

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

>код с goto в принципе не может быть читаем
может, но этому препятствует ограниченность мышления

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

golodranez, у тебя большое дублирование кода что значительно увеличивает вероятность ошибок, ухудшает читабельность итп. Вот это реально антипаттерн.

Тот пример с goto что привели это канонический паттерн реализации "эксепшенов" на C. Ничего плохого в нём нет. Это доказано многолетней практикой(асболютно все ядра сишных ОС содержат внутри goto, nginx, vsftpd итп).

Если ты хочешь доказать что goto не нужен то тебе нужно привести даже не сколько аналог того кода а свою реализацию экспешенов на C без goto. Без эксепшенов эта классическая задача высвобождения ресурсов нормально не решается. А построить эксепшены на сях без goto нельзя. Да и что такое эксепшн? По сути, это и есть goto который перемещает тебя на обработчик эксепшена.

Лучше забей на споры, от goto отказались исключительно потому что люди не умели им пользоваться. Криминала в его использовании нет. Ты же не утверждаешь что switch это полный пипец? А ведь оно реализовано точно так же по меткам как работает goto.

PS longjmp это тот же goto. Так даже в мане написано.

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

> 6 гото - вот это [сеnsored].. а количество точек возврата код не портит

ч0рт, ты либо тролль невероятной толщины, либо туп так же невероятно. Да тот же Дейкстра тебя убил бы: один из принципов структурного программирования - "процедура имеет ровно одну точку входа и ровно одну точку выхода" (да, были языки, в которых процедура могла иметь несколько точек входа). И этот принцип на порядок важнее принципа "не юзай goto".

> если тебе так не нравиться идеология Си,

"Без goto" - это идеология Си? :D Ты бредишь.

> то прогай на паскале.

Хм. На Паскале, говоришь? Ну тогда понятно.

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

>А на самом деле 6 раз close(fd), 4 -- unlink(path), 2 -- check_fail(), который ты выкинул.
т.е. тот код - это еще не всё? тогда ему незачОт!! мозги нам тут пудрит.

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

Чувак, запили SEH в ведре и гцц, обагри сорцы кровью еретиков. Это говорю тебе я, великий Дейкстра.

mannaz
()

(поправил форматирование)
вот вариант без goto и return:

int create_socket(const char *path, unsigned int perm, unsigned int nrlisten)
{
    bool res = false;
    struct sockaddr_un sockaddr;
    bool linked = false;
    int fd;
   
    for(;;)
    {
        if( fd = socket( AF_UNIX, SOCK_STREAM, 0 ) < 0 ||
            fcntl( fd, F_SETFL, O_NONBLOCK ) < 0 )
            break;

        sockaddr.sun_family = AF_UNIX;
        strncpy( sockaddr.sun_path, path, sizeof( sockaddr.sun_path ) - 1 );
        if( bind( fd, (struct sockaddr* )&sockaddr, SUN_LEN(&sockaddr) ) < 0 )
            break;

        linked = true;
        if( chmod( path, perm ) < 0 ||
            listen( fd, nrlisten ) < 0 )
            break;

        res = true;
        break;
    }

    // Clean
    if( !res )
    {
        if( fd >= 0 ) close( fd );
        if( linked ) unlink(path);
    }

    return res ? fd : -1;
}

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

>switch
>А ведь оно реализовано точно так же по меткам как работает goto.

да, причем, не самым эффективным образом, хотя иногда будет и получше многократных if-ов. (ключевое слово - иногда)
но суть-то не в этом. при использовании if и switch не приходится писать goto
хотя
"case бла-бла-бла:"
очень сильно напоминает метку для goto
"тра-ля-ля:"

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

> Линус от счастья описается)

ес-но - я же специально для него это написал ;)

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

Уже лучше. Только for (;;) {} с break'ами внутри -- тот же goto, только без ненавистного слова. 8))

Читаемость лучше не стала.

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

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

в целом выглядит лучше, чем у golodranez, но for(;;) сразу же ставит в недоумение. даже не смотря на то, что я привых к макросам в ядре в виде do {} while(0);
но это уже другая тема для срача...

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

чтоб никто не думал - вариант придуман исключительно от делать нечего и не претендует на реальное использование

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

Ну вот и я о том же :). Если нечто выглядит как go^ утка и крякает как утка то это go^утка :). Однако никто почему-то не возмущается по поводу switch.

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

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

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

> В той функции, я упразднил логирование каждой ошибки:

это ничего не меняет - просто +1 строка на каждую ошибку с log()

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

ну тут религиозные вопросы тоже рассматривались. Вот я это и написал к вопросам веры.

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

> о том, что if, switch, for и while тоже почти goto сейчас речи не идет :)

открыли, блин, истину :) факт в том-что "голый" goto гораздо эффективней позволяет запутать код, не так читабелен и может сделать выполнение кода чуть ли не рандомным

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

Ну да. он позволяет как всё запороть так и облегчить участь. Вся суть спора в том что есть люди которые не хотят верить в пользу goto, видят в нём только зло :).

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

>процедура имеет ровно одну точку входа и ровно одну точку выхода"

Большинство современных языков программирования мы можем выбросить на свалку? не пиши больше такую чушь

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

> не так читабелен

На вкус и цвет все фломастеры разные... Мне вариант с goto читать проще за счёт отсутствия "лишнего" уровня вложенности и "лишних" проверок. Судя по множеству OSS -- не только мне. 8))

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