Оборачивание C в C ++, просто для try / catch

Итак, у меня есть большой кусок унаследованного программного обеспечения, написанного на C. Это для встроенной системы, поэтому, если что-то пойдет не так, как деление на ноль, разыменование нулевого указателя и т. Д., Ничего не нужно делать, кроме перезагрузки.

Мне было интересно, смогу ли я реализовать просто main () как c ++ и обернуть его содержимое в try / catch. Таким образом, в зависимости от типа создаваемого исключения, я мог записать некоторую отладочную информацию непосредственно перед перезагрузкой.

Хм, так как есть несколько процессов, мне, возможно, придется обернуть каждый, не только main (), но я надеюсь, что вы понимаете, что я имею в виду ...

Стоит ли оставлять существующий код C (несколько сотен Kloc) нетронутым, кроме как обернуть его с помощью try / catch?

13.10.2009 08:53:07
Какие исключения вы планируете отловить? C не генерирует исключения C ++. Таким образом, ваш try / catch не будет ничего делать с ошибками, возникающими в C-коде.
jalf 13.10.2009 09:17:03
Обратите внимание, что VC6 неправильно попытался / поймал перехват исключений ОС, таких как нарушения прав доступа. Вы не должны полагаться на это поведение. Ваш компилятор будет иметь механизм для обработки исключений ОС.
peterchen 13.10.2009 09:35:36
Поймать нарушение доступа вряд ли можно считать неправильным. Поскольку нарушения доступа приводят к неопределенному поведению, может произойти все что угодно, включая выполняемый блок catch.
erikkallen 13.10.2009 11:52:56
Если ваша встроенная реализация C ++ генерирует исключения для нарушения прав доступа и деления на ноль, то вы можете попробовать скомпилировать весь этот код C как C ++, и в этом случае он внезапно начнет генерировать исключения. Вы должны проверить документы компилятора и надеяться, что нигде во всем этом коде C никто не использует «new» в качестве имени переменной. Код, скомпилированный как C, не будет генерировать исключения только потому, что он вызывается из C ++ - как это могло быть?
Steve Jessop 13.10.2009 12:17:54
7 ОТВЕТОВ
РЕШЕНИЕ

Деление на ноль или разыменование нулевого указателя не приводит к исключениям (используя терминологию C ++). C даже не имеет понятия об исключениях. Если вы работаете в UNIX-подобной системе, вы можете установить обработчики сигналов ( SIGFPE, SIGSEGVи т. Д.).

10
13.10.2009 08:58:47
ну, вы правы, jdl.co.uk/briefings/divByZeroInCpp.html поддержит вас. Я ранее кодировал обработчики сигналов / прерываний / аппаратных ошибок, но они o / s, даже h / w специфические. Полагаю, я задал довольно странный вопрос, извините. Я думаю, я просто надеялся, что перенос кода C в C ++ try / catch передаст магические свойства обработки ошибок. Может быть, это были плохие примеры, которые должны были быть специфичными для o / s & h / w, но могли бы попытаться / хотя бы помочь мне собрать некоторую отладочную информацию для других ошибок? например, трассировка стека, дамп реестра и т. д.?
user188946 16.10.2009 05:12:26
да, я знаю, что C никогда не выдаст исключение C ++. Но если я скомпилирую код C, как если бы он был C ++ (поскольку C является допустимым подмножеством C ++ (и многим программистам, когда им приказывают кодировать на C ++, просто переключают компиляторы и продолжают кодировать на C :-)), то обрабатывают C как если бы это был C ++ (возможно, придется переименовать все файлы, чтобы изменить C .c на * .cpp; может просто понадобиться использовать другой компилятор) *, тогда сгенерированный код будет готов к выполнению исключений, даже если я этого не сделаю изменить код Это то, чего я пытаюсь достичь - но я боюсь, что я не очень хорошо объясняю это ... извините
user188946 19.10.2009 02:17:43
Да, он будет готов генерировать исключения, но он не будет генерировать исключения самостоятельно. Вам придется либо использовать библиотеку, которая генерирует исключения, либо генерировать исключения вручную. Но если вы делаете это только для перезагрузки устройства, я не вижу выгоды. Вместо throw Something();тебя можно было позвонить ERROR();.
Lukáš Lalinský 19.10.2009 05:55:12

Поскольку это встроенное приложение, оно, вероятно, работает только на одной платформе.

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

В большинстве случаев это можно сделать всего несколькими строками кода. Проверьте, поддерживает ли ОС такие устанавливаемые обработчики исключений. Если вы работаете в системе без ОС, вы можете напрямую перехватывать прерывания процессора, которые вызываются во время исключений.

4
13.10.2009 08:58:12
«Поскольку это встроенное приложение, оно, вероятно, работает только на одной платформе». Какое странное утверждение!
Vicky 13.10.2009 09:09:01
Странный? По опыту это звучит очень правдоподобно. Я работал на крупного производителя телекоммуникаций, который запустил их 68030 ЦП с отключенным кешем, поскольку это сделало их «более совместимыми» с исходными 68000, которые они использовали ранее. Понятие «сбой приложения = перезагрузка устройства» также сильно намекает на устройство, созданное для одного приложения. Зачем выбирать две разные платформы для этого одного приложения? (Два поставщика, хорошо, но вы все равно выбрали бы двух поставщиков ARM или двух поставщиков MIPS)
MSalters 13.10.2009 09:34:26
Запуск встроенного программного обеспечения на одной платформе очень распространен. Обычно у вас есть дизайн с пользовательскими периферийными устройствами, которые вы не найдете в других местах, и он оптимизирован по стоимости (например, периферийные устройства, жестко подключенные к GPIO-контактам.) При изменении такой платформы с одной платформы на другую часто требуется полная перезапись по крайней мере IO- слой.
Nils Pipenbrinck 13.10.2009 10:30:47
Я согласен с тем, что существуют встроенные системы, которые предназначены только для одной платформы. Однако я не верю, что «поскольку это встроенное приложение, оно, вероятно, работает только на одной платформе», является действительным.
Vicky 14.10.2009 12:41:24
ОП: Я действительно привел плохие примеры с делением на ноль, пустой указатель, извините. давайте договоримся, что они должны обрабатываться сигналами / прерываниями / чем угодно. И давайте согласимся думать в общем случае (несколько платформ), нужно ли это или нет. Если я скомпилирую свой код на C как C ++, то компилятор сгенерирует броски по мере необходимости, и я могу добавить внешнюю оболочку try / catch. Кажется ли это, что это может быть полезно?
user188946 16.10.2009 05:20:09

Я не думаю, что машинный код, скомпилированный из C, делает то же самое в отношении исключений, как машинный код, скомпилированный для C ++, который «знает» об исключениях. То есть я не думаю, что было бы правильно ожидать, что я смогу отлавливать «исключения» из кода C, используя конструкции C ++. C не генерирует исключения, и нет ничего, что гарантировало бы, что ошибки, возникающие, когда код C делает что-то плохое, перехватываются механизмом исключений C ++.

3
13.10.2009 08:59:16
Согласен, C не имеет исключений. То, что я плохо объяснил, было то, что я хочу обернуть мой код C в C ++, таким образом превращаясь в код C ++ - который использует только небольшое подмножество языка, но который затем имеет обработку исключений, добавленную компилятором.
user188946 16.10.2009 05:14:28

Прежде всего, деление на ноль или разыменование нулевого указателя не вызовет исключений. Исключения Fpe реализованы в библиотеке GNU C с сигналами (SIGFPE). И являются частью стандарта C99, а не стандарта C ++.

Несколько советов, основанных на моем опыте разработки встроенных C и C ++. В зависимости от вашей встроенной ОС:

  • Если вы абсолютно не уверены в том, что делаете, не пытайтесь перехватывать потоки. Только внутри той же темы. Каждый поток обычно имеет свой собственный стек.
  • Бросок в середине унаследованного кода C и перехват может привести к проблемам, так как, например, когда вы перепрыгнули на блок catch из обычного потока программы, выделенная память может не быть восстановлена, таким образом, у вас есть утечки, которые далеко более проблематично, чем деление на ноль или разыменование нулевого указателя во встроенной системе.
  • Если вы собираетесь использовать исключения, добавьте их в свой код C ++ с выделением других ресурсов "C" в конструкторах и освобождением в деструкторах.
  • Лови их чуть выше слоя C ++.
4
13.10.2009 09:18:42

Я думаю, что я помню исследование того, как обрабатывать SIGSEGV(обычно генерируется при разыменовании неверного указателя или делении на 0), и общий совет, который я нашел в сети, был: ничего не делай, дай программе умереть. Объяснение, я думаю, правильное, состоит в том, что к тому времени, когда вы попадаете в ловушку SIGSEGV, стек нарушающего потока уничтожается и не подлежит восстановлению.

Кто-то может прокомментировать, если это правда?

0
13.10.2009 11:22:48
Он хотел перезагрузить устройство после получения SIGSEGV, а не пытаться его починить.
Lukáš Lalinský 13.10.2009 11:44:15
Я согласен - кроме как позволить этому умереть. На встроенных системах обычно требуется перезагрузка. Я просто надеялся собрать как можно больше отладочной информации, прежде чем умереть / перезагрузиться.
user188946 16.10.2009 05:22:00

Разделив на ноль, разыменование нулевого указателя - это не исключения C или C ++, а аппаратные исключения.

В Windows вы можете получить аппаратные исключения, подобные этим, в обычном C ++ исключении, если используется _set_se_translator ().

__try / __ catch также может помочь. Посмотрите __try / __ catch, GetExceptionCode (), _set_se_translator () на MSDN, вы можете найти то, что вам нужно.

1
13.10.2009 11:47:11

Работать только на MSVC

               
__пытаться
{

int p = 0;
р = р / 0;
}
__except (1)
{
printf («Деление на 0 \ n»);
}
0
20.10.2009 15:16:24