ANSI C эквивалент попробовать / поймать?

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

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

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

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

Вот код, с которым я работаю (довольно простой рекурсивный метод) и который я хотел бы обернуть с помощью 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();
}
 jalf21 сент. 2010 г., 21:05
Единственный известный мне язык, на котором можно скомпилировать код, опубликованный @aiden, - это C ++. И если это C ++, вы можете просто использоватьtry/catch, Если вам действительно нужно написать код ANSI C, то похоже, что вам придется переписать код набыть действительный C в дополнение к предложениям, сделанным в ответах.
 anijhaw21 сент. 2010 г., 18:59
nicemice.net/cexcept то, что может быть полезным
 David Thornley21 сент. 2010 г., 19:10
@ Стив: Хорошая мысль. Мой ответ был специально для C, а не для любой формы C ++, независимо от того, как C-like.
 Steve Jessop21 сент. 2010 г., 18:59
Этот код не C, ANSI или иначе. С не имеет:: Оператор области
 Kel21 сент. 2010 г., 19:02
C не имеет механизма обработки исключений. Вся обработка ошибок обычно выполняется с помощью возвращаемых значений и переменной errnum. Кстати, было бы неплохо получить подробные комментарии экспертов о том, как правильно обрабатывать ошибки в C :)

Ответы на вопрос(8)

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

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

Есть классическая раскрутка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 */
  }
 /* ... */
}

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

 jamesdlin21 сент. 2010 г., 21:41
goto это способ пойти (извините за каламбур) в C. Однако наличие нескольких меток выхода кажется излишним. Чистее (хотя и несколько менее эффективно) иметь одну метку выхода и (при необходимости) проверять, какие ресурсы были выделены.
 dmckee21 сент. 2010 г., 21:50
@jamesdlin: несколько ярлыков покупают что-то конкретное: каждый соответствует ресурсу, который, возможно, потребуется выпустить. Вы можете избежать их с помощью условных выражений в выпусках, но в некоторых случаях (не в этом), которые требуют дополнительных флагов. Дело вкуса, насколько я могу судить.
 Steve Jessop22 сент. 2010 г., 17:58
@jamesdlin: когда я выполнял этот стиль очистки (обычно в ассемблере, а не в C), я обнаружил, что версия goto более чистая и простая в тех случаях, когда потенциальные ресурсы всегда распределяются в одном и том же порядке. Вы можете легко узнать, какойgotoпотому что в любой момент кода вы понимаете, какие ресурсы у вас есть (я надеюсь).
 James21 сент. 2010 г., 21:30
Ик! Это выглядит очень грязно для меня. Я предпочитаю свой метод, который я предложил ниже. Нет необходимости идти!
 jamesdlin21 сент. 2010 г., 22:41
Да, но это требует дополнительной сложности, и поддерживать IMO немного сложнее (потому что порядок важен). В большинстве случаев дополнительные флаги (и дополнительные проверки) все равно не нужны; функции очистки (неfclose) обычно должно быть no-ops, если оно вызывается для фиктивных значений (например,NULL).

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

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

 John Dibling21 сент. 2010 г., 19:12
Кто-то хочет тебя достать?
 Steve Townsend21 сент. 2010 г., 19:15
@ Джон Диблинг - это само собой разумеется ... Буду следить, может быть, просто плохой день.
 Steve Townsend21 сент. 2010 г., 19:09
Хм, третье понижение сегодня. Есть какая-то конкретная причина для этого? Я думал, что это выглядело многообещающе.
 Hogan21 сент. 2010 г., 19:12
+1 потому что отрицательное голосование было неправильным ... идеальная ссылка на вопрос

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

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

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

 sbi21 сент. 2010 г., 20:22
IME обычный способ указать на ошибки или ошибки в C - это вернуть значение, которое игнорирует вызывающая сторона.:(
 paercebal22 сент. 2010 г., 13:32
@sbi: IME, некоторые люди все еще верят, что «вернуть значение» - это путь в C ++, Java и C #, тоже ...:(
 sbi22 сент. 2010 г., 13:53
@paercebal: я знаю.:(

который мне нравится использовать, заключается в следующем. Я не знаю, есть ли у него конкретное имя, но я столкнулся с ним, когда я занимался обратным проектированием некоторого ассемблерного кода в эквивалентный 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;
}
 dmckee21 сент. 2010 г., 21:47
Ницца. Вам могут понадобиться вложенные экземпляры, если вам нужно условно раскрутить материал.

/ Catch, вы можете переделать работу Бьярна Страуструпа и написать препроцессор, чтобы сделать это.

 sbi21 сент. 2010 г., 20:24
@Nemanja: Это действительно так для оригинального cfront.Comeau C ++однако, все еще выводит C-код. (Потому что это обеспечивает высокую переносимость.) Но я сомневаюсь, что это более полезно, чем вывод на ассемблере любого другого компилятора: это машинно-сгенерированный код, и как таковой он не предназначен для использования человеком.
 Nemanja Trifunovic21 сент. 2010 г., 19:31
К тому времени, когда исключения были введены в C ++, реализация C-препроцессора стала историей.
 Jonathan Leffler21 сент. 2010 г., 21:05
Я полагаю, что исключения были той соломинкой, которая сломала спину верблюду, где верблюд был компилятором cfront C ++. Смотрите Stroupstrup "Дизайн и развитие C ++".

exceptions4c.

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

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

Ваш ответ на вопрос