try catch в кроccплатформенных исходниках

Постараюсь коротко. Думаю что всем программистам на Си с детства знакома подобная конструкция:

try {
  ...
}
catch(...) {
  printf("error\n");
}

Назначение её в том чтобы не уронить программу в случае ошибки в коде. По крайней мере обычно так это происходит под Windows. Под Linux, или просто GCC компилятором, дела обстоят совсем иначе. GCC благополучно игнорирует любые ошибки внутри try и программа с грохотом падает. С сам catch реагирует только на программные исключения (которые я за жизнь применять только раз, и то заменял им множество переходов по метке). Конешно кто-то может сказать что это правильно и ближе к стандарту. А для программы, которая повредила свои данные, наилудший выход - совершить харакири. Приведу простой пример. Есть некая программа которая получает котировки по курсу валют, и есть в ней такая интересная фукнция, как проговаривание этих котировок в слух. Сама звуковая система устроена прямо скажем не просто (надо чтобы она произносила цифры, весила мало, и можно было вставлять другие языки. А попросту содержит в себе кодек, работающий с файлом похожим на базу). Предположим что в ней всё таки нашлась некая ошибка, которую сразу не заметили. Здесь и приходит на выручку знаменитый try. И смысл его не в том чтобы проигнорировать проблему, а в том чтобы насовсем заблокировать злощастную речевую систему, и сообщить об этом, в том случае если в ней были замечены какие-то проблемы. это позволит не уронить программу в отвественный момент. В принципе если программа написана совсем криво, то она может и порушить свои данные (хотя и целостность важных данных тоже контролировать не сложно). Ну а в целом подобный трюк работает хорошо и не спасает только в самых экзотических случаях.

Так вот, повторю ещё раз. В GCC try не работает. Всё что можно сделать, это обработать сигнал и сделать что-то отдалённо похожее:

sigjmp_buf buf;
void hand(int sig)
{
   printf("signal: %d\n",sig);

   siglongjmp(buf1,1);
}


int main()
{
   struct sigaction act; memset(&act,0,sizeof(act));
   act.sa_handler=hand;
   sigaction(SIGFPE,&act,0);
   if(sigsetjmp(buf,1)) printf("Что-то работало не так! ;)\n\a"); 
   else {
      n=n/0;
   }   
   return 0;
}

throw внутри сигнала, послать так же не получится. К тому же встаёт ещё одна проблема. В программе может быть очень много потоков, а обработчик сигналов у нас один на всех. В прочем как известно обычно и в Windows обработчик исключения один на всю программу (меняется только его реакция на ошибку). Спасает нас то обстоятельство, что поток вызвавший исключение (сигнал), очень легко определить. Функция pthread_self(); внутри обработчика сигнала, однозначно расскажет из какого потока пришёл этот сигнал. А для того чтобы не вставлять в обработчик всякие std::map и не следить за завершением каждого потока, значение sigjmp_buff можно прикрепить к самому потоку.

Конечный исходник

Простой пример. Данный исходник не позволяет делать вложенных try блоков:

Исходник позволяющий делать вложенные try блоки:


Последний исходник так же позволяет делать блоки с автоматической блокировкой. Например:
_try_safe {
  n=n/m
} _catch_safe {
  printf("error\n");
} _final_safe

В данном случае если внутри _try_safe случится деление на ноль. То будет вызван _catch_safe блок. А кроме того весь кусок кода заблокируется автоматически, т.е. при повторном исполнении эти строки уже будут восприниматься как пустое место и выполняться не станут. Делается это с помощью статических переменных внутри блока. Часто столько простыми действиями ничего не обходится, но показать это стоило.

В теории можно было подменить даже обычный try. Потому что любой Си позволяет переопределять ключевые слова, подменяя их свойства. Можете сами попробовать:
#define try printf("[try]"); try
#define break printf("[break]"); break

Поправки

В BeOS: posix вариант работает только в свежих версиях Hauku. В более ранних билдах обработка сигналов работала неправильно. А в Pe, и Dano версиях вообще небыло обработки сигналов, а так же нормальных механизмов для их замены, не считая встроенной системы отладки (которая для этого мало подходит).


[Proteus 29.10.2007] icq:133575351 lawnmower-man@mail.ru

Hosted by uCoz