LINUX.ORG.RU

Обработка ошибок с помощью макросов

 , ,


0

3

Привет, Котаны!
Есть такой код:

func1()
{
  int __result_=SUCCESS;
  char *buff=malloc(5);
  char *buff1=malloc(5);
  int i;
  for(i=0;i<5;i++)
  {
    int j;
    for(j=0;j<5;j++)
    {
      if((__result_=func())!=SUCCESS)
        goto __release_;
    }
  }

  __release_:
    free(buff);
    free(buff2);
    return __result_;
}

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

#define RETINIT __result_=SUCCESS
#define CHECK(X) if(__result_=X)!=SUCCESS) goto __release_
#define RETURN(X) __release_: X return __result_

Тогда получится:

func1()
{
  RETINIT;

  char *buff=malloc(5);
  char *buff1=malloc(5);
  int i;
  for(i=0;i<5;i++)
  {
    int j;
    for(j=0;j<5;j++)
    {
      CHECK(func());
    }
  }

  RETURN(
  {
    free(buff);
    free(buff2);
  });
}

Но есть проблема. Как вы догадались, этот код использовать нельзя. Кто догадался - молодец, кто не догадался - объясняю: если этот код использовать в десяти функциях, то при выполнении посылать нас будет на первый goto - краш стэка, очистка неизвестно чего... Последствия понятны.

Как решать?

★★

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

Привет, мышан!

Я так и делаю. Ты же не используешь Longjump! А метка для goto действительна лишь внутри одной функции. Только макросы на всякий пожарный в do{}while(0) оберни.

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

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

sambist ★★
() автор топика

Если ты хочешь поиметь исключения, то либо используй язык, который их поддерживает, либо велосипедь сам, например, через джампы. Ну или просто забей.

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

Надо было вбивать живой пример. Ты же хочешь, чтобы тебе помогли, али как?

i-rinat ★★★★★
()
Ответ на: комментарий от sambist

А вот тебе ответ про goto:

$ cat q.c
#include <stdio.h>
void f1(int a) {
  if (a == 3)
    goto done;
cycle:
  goto cycle;
done:
  printf("f1\n");
  return;
}

void f2(int a) {
  if (a == 4)
    goto done;
cycle:
  goto cycle;
done:
  printf("f2\n");
  return;
}

int main(void) {
  f1(3);
  f2(4);
  printf("ok\n");
  return 0;
}
$ gcc q.c
$ ./a.out 
f1
f2
ok
$ 

Как видишь, одинаковые метки в разных функциях работают «как надо».

i-rinat ★★★★★
()
#define CHECK(X) if(__result_=X)!=SUCCESS) goto __release_

Убивал бы за такие макросы! Никто не будет разгребать что значат твои CHECK() и FUCK() по всему проекту. Как поставить бряк посредине твоей велосипедистой конструкции?

Вот канонічный способ проверки кодов возврата, такой код поймет любой сишник после беглого взгляда:

int myfunc1()
{
    int ret = 0;

    if ((ret = myfunc2()) < 0) goto err;
    if ((ret = myfunc3()) != STATUS_OK) goto err;

err:
    // здесь освобождают ресурсы и т.д.
    free(allshit);
    return ret;
}
Вкратце: километровые макросы - плохо, goto err - OK.

И еще: __переменные начинающиеся с двойного подчеркивания зарезервированы для компилера/рантайма согласно стандарту.

mtk
()

кто не догадался - объясняю

Тебе еще рано объяснять, ты лучше спрашивай. Чем с уверенным видом дампить сюда бредовые домыслы, лучше бы трейс выложил.

arturpub ★★
()

кто не догадался - объясняю: если этот код использовать в десяти функциях, то при выполнении посылать нас будет на первый goto - краш стэка, очистка неизвестно чего... Последствия понятны.

OMFG какой бред.

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

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