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();
}
8 ответов
Как правило, нет.
Можно использовать setjmp
а также longjmp
создать что-то похожее на try/catch, хотя в C нет такой вещи, как деструкторы или разматывание стека, поэтому о RAII не может быть и речи. Вы могли бы даже приблизить RAII с помощью так называемого "стека очистки" (см., Например, Symbian/C++), хотя это не очень близкое приближение, и это большая работа.
Обычный способ указать на ошибки или ошибки в C - это вернуть значение, указывающее статус успеха. Вызывающие стороны проверяют возвращаемое значение и действуют соответственно. Смотрите, например, стандартные функции C: printf
, read
, open
, для идей, как указать свои функции.
При смешивании кода C и C++ вы должны убедиться, что исключение C++ никогда не достигнет кода C. При написании функций C++, которые будут вызываться из C, ловите все.
C не поддерживает обработку исключений.
Здесь есть информация об одном подходе к этой проблеме. Это показывает простой setjmp/longjmp
подход, но также предоставляет более сложную альтернативу, подробно рассмотрены.
Есть классическая раскрутка 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 */
}
/* ... */
}
но ни один из подходов не является полностью эквивалентным. Вы должны управлять всеми ресурсами самостоятельно, вы не получите автоматический откат до тех пор, пока не будет найден обработчик, и так далее...
Один полезный стиль кодирования, который мне нравится использовать, заключается в следующем. Я не знаю, есть ли у него конкретное имя, но я столкнулся с ним, когда я занимался обратным проектированием некоторого ассемблерного кода в эквивалентный 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;
}
Это моя реализация системы обработки исключений в C: exceptions4c.
Он работает на макросах, построен на вершине setjmp
а также longjmp
и это 100% портативный ANSI C.
Там вы также можете найти список всех различных реализаций, которые я знаю.
Вы можете найти возможную реализацию с longjmp в этой книге: Интерфейсы и реализации C: методы создания программного обеспечения многократного использования - Дэвид Хэнсон
И вы можете найти код здесь и здесь в качестве примера стиля, используемого в книге.
Если вы хотите сделать многоуровневый прыжок, посмотрите вверх setjmp()
а также longjmp()
, Их можно использовать как примитивное исключение. setjmp()
Функция устанавливает возврат к месту и возвращает значение статуса. longjmp()
Функция переходит на место возврата и предоставляет значение статуса. Вы можете создать catch
функция, вызвав после setjmp()
в зависимости от значения статуса.
По какой-то причине не используйте их в C++. Они не выполняют раскручивание стека и не вызывают деструкторы.
Поскольку C++ изначально был реализован как препроцессор C и имел Try / Catch, вы можете переделать работу Бьярна Страуструпа и написать препроцессор, чтобы сделать это.