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();
}
Ответы
Ответ 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 */
}
/* ... */
}
но ни один из подходов не является полностью эквивалентным. Вы должны управлять всеми ресурсами самостоятельно, вы не получаете автоматический откат до тех пор, пока не будет найден обработчик, и так далее...
Ответ 6
Вы можете найти возможную реализацию с longjmp в этой книге: C Интерфейсы и реализации: методы создания многоразового программного обеспечения - David Hanson
И вы можете найти код здесь и здесь в качестве примера стиля, используемого в книге.
Ответ 7
Если вы хотите совершить прыжок с несколькими уровнями, найдите setjmp()
и longjmp()
. Они могут использоваться как примитивный бросок исключения. Функция setjmp()
устанавливает возвращаемое место и возвращает значение статуса. Функция longjmp()
переходит к месту возврата и предоставляет значение статуса. Вы можете создать функцию catch
, вызвав ее после setjmp()
в зависимости от значения состояния.
Не по какой-либо причине использовать их в С++. Они не выполняют разматывание стека или деструкторы вызовов.
Ответ 8
Так как С++ первоначально был реализован как предварительный процессор C, и у него был Try/Catch, вы могли бы переделать работу Bjarne Stroustrup и написать предварительный процессор, чтобы сделать это.