Подтвердить что ты не робот

ANSI C эквивалент try/catch?

У меня есть код C, с которым я работаю, и я нахожу ошибки, когда код работает, но мало информации о том, как сделать правильный try/catch (как на С# или С++).

Например, в С++ я просто сделал:

try{
//some stuff
}
catch(...)
{
//handle error
}

но в ANSI C я немного потерян. Я пробовал некоторые онлайн-поиски, но я не вижу достаточной информации о том, как это произошло/фигура. Я бы спросил здесь, если кто-то может указать мне в правильном направлении.

Вот код, с которым я работаю (довольно простой, рекурсивный метод) и хотел бы обернуть с помощью try/catch (или эквивалентной структуры обработки ошибок).

Однако мой главный вопрос заключается в том, как сделать try/catch в ANSI C... реализация/пример не обязательно должна быть рекурсивной.

void getInfo( int offset, myfile::MyItem * item )
{
    ll::String myOtherInfo = item->getOtherInfo();
    if( myOtherInfo.isNull() )
        myOtherInfo = "";
    ll::String getOne = "";
    myfile::Abc * abc = item->getOrig();
    if( abc != NULL )
    {
        getOne = abc->getOne();
    }
    for( int i = 0 ; i < offset ; i++ )
    {
             printf("found: %d", i);
    }
    if( abc != NULL )
        abc->release();
    int childCount = item->getChildCount();
    offset++;
    for( int i = 0 ; i < childCount ; i++ )
        getInfo( offset, item->getChild(i) );
    item->release();
}
4b9b3361

Ответ 1

Как правило, вы этого не делаете.

Можно использовать setjmp и longjmp для создания чего-то достаточно похожего на try/catch, хотя в C нет такой вещи, как разрушители или стекирование, поэтому RAII не может быть и речи. Вы даже можете приблизиться к RAII с так называемым "стеком очистки" (см., Например, Symbian/С++), хотя это не очень близкое приближение, и это много работает.

Обычный способ указания ошибок или сбоев на C - это вернуть значение, указывающее статус успеха. Абоненты проверяют возвращаемое значение и действуют соответственно. См., Например, стандартные функции C: printf, read, open, для идей, как указать ваши функции.

При смешивании кода C и С++ вы должны убедиться, что исключение С++ никогда не достигает кода C. При написании функций С++, которые будут вызываться из C, поймайте все.

Ответ 2

C не поддерживает обработку исключений.

Существует информация об одном подходе к этой проблеме здесь. Это показывает простой подход setjmp/longjmp, но также предоставляет более сложную альтернативу, покрытую глубиной.

Ответ 3

Это моя реализация системы обработки исключений в C: exceptions4c.

На нем работают макросы, построенные поверх setjmp и longjmp, и это 100% портативный ANSI C.

Там вы также можете найти список всех различных реализаций, о которых я знаю.

Ответ 4

Один полезный стиль кодирования, который мне нравится использовать, следующий. Я не знаю, имеет ли оно конкретное имя, но я натолкнулся на него, когда я перепроектировал код сборки в эквивалентный код C. Вы теряете уровень отступов, но это не так уж и важно для меня. Следите за рецензентом, который укажет на бесконечный цикл!:)

int SomeFunction() {
    int err = SUCCESS;

    do {
        err = DoSomethingThatMayFail();
        if (err != SUCCESS) {
            printf("DoSomethingThatMayFail() failed with %d", err);
            break;
        }

        err = DoSomethingElse();
        if (err != SUCCESS) {
            printf("DoSomethingElse() failed with %d", err);
            break;
        }

        // ... call as many functions as needed.

        // If execution gets there everything succeeded!
        return SUCCESS;
    while (false);

    // Something went wrong!
    // Close handles or free memory that may have been allocated successfully.

    return err;
}

Ответ 5

Существует классический раскручивающий шаблон goto:

FILE *if = fopen(...);
FILE *of = NULL;
if (if == NULL) return; 

of = fopen(...);
if (of == NULL) goto close_if;

/* ...code... */
if (something_is_wrong) goto close_of;

/* ... other code... */

close_of:
  fclose(of);
close_if:
  fclose(if);

return state;

В качестве альтернативы вы можете подделать его ограниченным образом, выделив код "try" в другой функции

int try_code(type *var_we_must_write, othertype var_we_only_read /*, ... */){
  /* ...code... */
  if (!some_condition) return 1;
  /* ...code... */
  if (!another_condition) return 2;
  /* ...code... */
  if (last_way_to_fail) return 4;
  return 0;
}

void calling_routine(){
  /* ... */
  if (try_code(&x,y/*, other state */) ) {
     /* do your finally here */
  }
 /* ... */
}

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

Ответ 7

Если вы хотите совершить прыжок с несколькими уровнями, найдите setjmp() и longjmp(). Они могут использоваться как примитивный бросок исключения. Функция setjmp() устанавливает возвращаемое место и возвращает значение статуса. Функция longjmp() переходит к месту возврата и предоставляет значение статуса. Вы можете создать функцию catch, вызвав ее после setjmp() в зависимости от значения состояния.

Не по какой-либо причине использовать их в С++. Они не выполняют разматывание стека или деструкторы вызовов.

Ответ 8

Так как С++ первоначально был реализован как предварительный процессор C, и у него был Try/Catch, вы могли бы переделать работу Bjarne Stroustrup и написать предварительный процессор, чтобы сделать это.