Как мне обрабатывать исключения на процедурном языке? - PullRequest
3 голосов
/ 15 сентября 2009

Как мне выполнить обработку исключений на процедурном языке, таком как C или Perl? (Я знаю, что Perl также выполняет OO.) Как лучше всего обрабатывать исключения в процедурном коде в Perl?

Ответы [ 6 ]

7 голосов
/ 15 сентября 2009

В Perl 5 обработка исключений выполняется с использованием eval и die. Вы просто проверяете тело кода и, если он умирает, вы можете проверить $@ на наличие ошибки. Это не совсем легко, если вы хотите сделать это правильно, поэтому существуют различные модули try / catch. Возможно, вас заинтересует Try :: Tiny , который не имеет зависимостей и описывает все хитрости, с которыми вам приходится иметь дело при использовании наивной обработки исключений eval. (Также см. это сообщение в блоге автором Try :: Tiny.)

2 голосов
/ 15 сентября 2009

Вот пример того, как я делаю исключения в Perl (без использования одного из модулей Try):

use Carp;
use English qw( -no_match_vars );

do_something_needing_rollback_if_failed();
eval {
    do_something_dangerous();
} or do {
   # Exception was thrown by dangerous method
   # Save the error:
   my $error = $EVAL_ERROR;

   # Try to rollback
   eval { rollback(); }
     or do { confess qq{Couldn't rollback: $EVAL_ERROR. Original error $error}; }

   # Let's rethrow:
   confess qq{Rolled back! Error was $error};
}

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

1 голос
/ 16 сентября 2009

В Perl, как обычно, есть несколько способов сделать это. Однако сообщество разработчиков в целом решило, как сделать большинство вещей.

Я становлюсь поклонником Exception :: Base себя.

Если вам нужна более легкая реализация, просто используйте Carp.

Вы перехватываете исключения, используя конструкцию eval { ... }; if ($@) { ... }.

С Exception :: Base он предлагает способ абстрагирования конструкции if ($@) { ... } для вас. Вам все равно нужно будет использовать eval { ... }.

1 голос
/ 15 сентября 2009

В C были setjmp и longjump; по сути, setjmp () сохраняет текущий контекст в стеке, а longjmp () может вернуться к точке, сохраненной setjmp (). Запись в Википедии о тех деталях красиво заполняет.

1 голос
/ 15 сентября 2009

Это скорее зависит от того, что вы подразумеваете под «обработкой исключений».

Некоторые ОС имеют механизмы исключения - см. Подпрограммы обработки исключений Windows или Обработчики сигналов Linux (некоторые из которых являются исключениями).

Если вы подразумеваете идиому в пользовательском коде, чтобы сигнализировать об ошибке и разматывать стек для очистки любых выделенных объектов, то код C не вызывает деструкторы для выделенных объектов, когда стек разматывается (он просто восстанавливает память), поэтому в C это нормально, чтобы функции возвращали значение состояния, а вызывающий код выполняет какую-либо очистку, требуемую перед возвратом.

Я не очень хорошо знаю Perl, но поиск в Google для «обработки исключений Perl» указывает, что он имеет как встроенные механизмы, эквивалентные try / catch, так и модули, которые обеспечивают обработку исключений «OO style».

0 голосов
/ 15 сентября 2009

Традиционный подход состоит в том, чтобы ... ну ... а не:)

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

int try_it() {
  if (!do_something(...)) {
     return TRYIT_FAILURE;
  }
}

void my_gui() {
  rc = try_it()
  if (rc == TRYIT_FAILURE) {
    message_box("failed when trying it.", MB_ABORT|MB_RETRY);
  }
  ...
}

Вы также можете сделать это в большой функции, используя вложенные ifs, если вы хотите что-то вроде try ... кроме конструкции:

if (stage1()) {
   if (stage2()) {
       if(stage3()) {
           printf("success!\n");
       } else {
           // error handling for stage 3
       }
   } else {
       // error handling for stage 2
   }
} else { 
   // error handling for stage 1
}

И вы можете сделать то же самое с gotos, если вы немного злитесь.

Однако вы можете делать реальные исключения, по крайней мере, в C. В C есть два стандартных вызова библиотеки для такого рода вещей: setjmp и longjmp. С их помощью вы можете перепрыгнуть через несколько вызовов функций в заранее определенное место, где вы знаете, что произошло исключение (прыжок). См. Setjmp.h # exception_handling в Википедии , чтобы узнать больше об этом.

Кажется, у Perl есть способ сделать это, хотя это выглядит далеко не интуитивно для меня. Опять же, я не кодирую в Perl:)

FAQ по Perl Q4.8

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...