Обработка исключений C. Программирование на C и C++ для новичков
Обработка исключительных ситуаций в С — это процесс, который пригодится каждому программисту на этом языке.
Обработка исключений в С и С++
Обработка исключительных ситуаций в С применяет 3 основных и важных слова:
try — блок, в коде которого будут искаться ошибки;
catch — блок, который знает, что делать с найденными ошибками;
throw — оператор, который принудительно вбрасывает ошибку в программу для возбуждения работоспособности try и catch и генерации точки входа обработки исключений.
Обработка исключений в С имеет довольно простой принцип:
Код, в котором мы ожидаем появление ошибок (они же исключения!), помещается в блок try. Когда в этом блоке обнаруживается исключение (ошибка), то оно перехватывается подходящей инструкцией catch и обрабатывается.
Блоки try и catch генерируются по следующей форме:
try {
//код-инструкция, который нужно обработать на исключения
catch ( описание типа и аргумента) {
//инструкция блока catch }
catch ( описание типа и аргумента) {
//инструкция блока catch }
}
Блок try может быть разных размеров. Он может содержать в себе лишь часть какой-нибудь функции, которую нужно проверить на ошибки, а может содержать весь блок main(), то есть охватить обработку исключений всей программы.
Когда в try будет найдена какая-то ошибка, она будет перехвачена блоком catch, который обладает соответствующей инструкцией. То есть для одного try может быть написано множество catch для обработки разных типов исключений. Один catch = один тип исключений (ошибок). Соответственно, catch исполняется, только когда его инструкции соответствуют найденной ошибке в try.
А если в блоке try не будут найдены никакие исключения, то никакой catch выполняться не будет.Бывает такое, что в программе находятся ошибки, для которых нет инструкций catch. В этом случае программа может завершиться в аварийном режиме.
Когда найденная ошибка в блоке try передается соответствующей инструкции catch, вся программа приостанавливает свою работу и ждет завершения работы блока catch. Ошибка, прошедшая catch, считается обработанной, и после окончания работы этого блока возобновляется работа всей обрабатываемой программы.
Обработка исключений в С: блок catch
С блоком try все ясно — там может быть любой объем кода, который нужно проверить на исключения. Но что может быть в блоке catch? В принципе там можно написать любую нужную инструкцию или же вообще блок можно оставить пустым. Но чаще всего эти блоки выполняют три основные вещи:
Выводят сообщение об исключениях в Консоль или лог-документ.
Возвращают значение и код ошибки обратно в cаller.
Генерируют другое исключение для отправки его в другой блок try.
Заключение
Обработка исключений в С — это несложная операция. Чтобы начать ее применять, нужно запомнить 3 основные вещи:
Когда используется оператор throw, то обработка исключений начинается в тот же момент с ближайшего блока try, даже если он находится выше по стеку. Если в этом try есть инструкция catch для обработки данного исключения, то точка входа программы перейдет в данный обработчик. А само вброшенное исключение будет считаться обработанным.
Если в ближайшем try не будет нужных обработчиков catch для вброшенного исключения, то программа начнет выполняться со следующего try. И так до тех пор, пока не будет найден нужный catch и не определится точка входа программы.
Тип исключения и тип обработчика должны совпадать. К примеру, если ошибка типа float, то она не обработается catch типом int, а если исключение типа int — никогда не обработается catch типом char и т. д.
НОУ ИНТУИТ | Лекция | Отладка и обработка исключительных ситуаций
< Лекция 25 || Лекция 23: 123456
Аннотация: Корректность и устойчивость. Cпецификация системы. Корректность и устойчивость программных систем. Исключительные ситуации. Обработка исключительных ситуаций. Жизненный цикл программной системы. Три закона программотехники. Отладка. Создание надежного кода. Искусство отладки. Отладка и инструментальная среда Visual Studio .Net.
Ключевые слова: корректность, устойчивость, спецификации, отладка, исключительная ситуация, обработка исключений, IBM, операционная система, OS/360, жизненный цикл, повторное использование, закон для разработчика, закон для пользователя, закон чечако, минимум, надежный код, статический контроль типов, динамическое связывание, полиморфизм, автоматическая сборка мусора, тестеры, корректность программы, две группы средств, программные средства, отладочная печать, механизм условной компиляции, константы условной компиляции, атрибут языка, методы печати данных, методы доказательства правильности программ, метод Флойда, отладочное сообщение, программотехника, запись, базы данных, тип исключения, схема без возобновления, блоки-обработчики исключительных ситуаций, выбрасывание исключений, класс Exception, классы исключений, «захват» исключения, универсальный обработчик, специализированные обработчики, охраняемые блоки, Проектирование по Контракту, схема Бертрана
Корректность и устойчивость программных систем
intuit.ru/2010/edi»>Корректность и устойчивость — два основных качества программной системы, без которых все остальные ее достоинства не имеют особого смысла. Понятие корректности программной системы имеет смысл только тогда, когда задана ее спецификация. В зависимости от того, как формализуется спецификация, уточняется понятие корректности.В лекции 10 введено строгое понятие корректности метода по отношению к его спецификациям, заданным в виде предусловия и постусловия метода. |
Корректность — это способность программной системы работать в строгом соответствии со своей спецификацией. Отладка — процесс, направленный на достижение корректности.
Во время работы системы могут возникать ситуации, выходящие за пределы, предусмотренные спецификацией. Такие ситуации называются исключительными.
Устойчивость — это способность программной системы должным образом реагировать на исключительные ситуации. Обработка исключительных ситуаций — процесс, направленный на достижение устойчивости.Почему так трудно создавать корректные и устойчивые программные системы? Все дело в сложности разрабатываемых систем. Когда в 60-х годах прошлого века фирмой IBM создавалась операционная система OS-360, то на ее создание потребовалось 5000 человеко-лет, и проект по сложности сравнивался с проектом высадки первого человека на Луну. Сложность нынешних сетевых операционных систем, систем управления хранилищами данных, прикладных систем программирования на порядки превосходит сложность OS-360, так что, несмотря на прогресс, достигнутый в области технологии программирования, проблемы, стоящие перед разработчиками, не стали проще.
Жизненный цикл программной системы
Под » жизненным циклом » понимается период от замысла программного продукта до его «кончины».
Проектирование <-> Разработка <-> Развертывание и Сопровождение
Все это называется циклом, поскольку после каждой фазы возможен возврат к предыдущим этапам. В объектной технологии этот процесс является бесшовным, все этапы которого тесно переплетены. Не следует рассматривать его как однонаправленный — от проектирования к сопровождению. Чаще всего, ситуация обратная: уже существующая реализация системы, прошедшая сопровождение, и существующие библиотеки компонентов оказывают решающее влияние на то, какой будет новая система, каковы будут ее спецификации.
Вот некоторые типовые правила, характерные для процесса разработки ПО:
- Уделяйте этапу проектирования самое пристальное внимание. Успех дела во многом определяется первым этапом. Нет смысла торопиться с переходом на последующие этапы, пока не составлены ясные и четкие спецификации. Ошибки этого этапа — самые дорогие и трудно исправляемые.
- Помните о тех, для кого разрабатывается программный продукт. Идите «в люди», чтобы понять, что нужно делать. Вместе с тем, не следует полностью полагаться на пользователей — их опыт консервативен, новые идеи могут часто приходить от разработчиков, а не от пользователей.
- Разработка не начинается «с нуля». Только используя уже готовые компоненты, можно своевременно создать новую систему. Работая над проектом, думайте о будущем, создавайте компоненты, допускающие их повторное использование в других проектах.
- Создавайте как можно раньше прототип своей системы и передавайте его пользователям в опытную эксплуатацию. Это поможет устранить множество недостатков и ошибок в заключительной версии программного продукта.
- Какие бы хорошие спецификации не были написаны, какими бы хорошими технологиями и инструментами не пользовались разработчики, какими бы профессионалами они ни были — этого еще не достаточно для успеха дела. Необходимым условием является управление проектом, наличие специальных средств управления. Но и этого не достаточно. Третьим важным фактором является существование команды. Коллектив разработчиков должен представлять собой единый коллектив. Умение работать в команде так же важно, как и профессиональные навыки разработчика.
Три закона программотехники
Первый закон (закон для разработчика)
Корректность системы — недостижима. Каждая последняя найденная ошибка является предпоследней.
Этот закон отражает сложность нетривиальных систем. Разработчик всегда должен быть готов к тому, что в работающей системе имеются ситуации, в которых система работает не в точном соответствии со своей спецификацией, так что от него может требоваться очередное изменение либо системы, либо ее спецификации.
Второй закон (закон для пользователя)
Не бывает некорректных систем. Каждая появляющаяся ошибка при эксплуатации системы — это следствие незнания спецификации системы.
Есть два объяснения справедливости второго закона. Несерьезное объяснение состоит в том, что любая система, что бы она ни делала, при любом постусловии корректна по отношению к предусловию False, поскольку невозможно подобрать ни один набор входных данных, удовлетворяющих этому предусловию. Так что все системы корректны, если задать False в качестве их предусловия. Если вам пришлось столкнуться с системой, предусловие которой близко к False, то лучшее, что можно сделать, это отложить ее в сторону и найти другую.
Более поучительна реальная ситуация, подтверждающая второй закон и рассказанная мне в былые годы Виталием Кауфманом — специалистом по тестированию трансляторов. В одной серьезной организации была разработана серьезная прикладная система, имеющая для них большое значение. К сожалению, при ее эксплуатации сплошь и рядом возникали ошибки, из-за которых организация вынуждена была отказаться от использования системы. Разработчики обратились к нему за помощью. Он, исследуя систему, не внес в нее ни строчки кода. Единственное, что он сделал, это описал точную спецификацию системы, благодаря чему стала возможной нормальная эксплуатация.
Обратите внимание на философию, характерную для этих законов: при возникновении ошибки разработчик и пользователь должны винить себя, а не кивать друг на друга. Так что часто встречающиеся фразы «Ох уж эта фирма Чейтософт — вечно у них ошибки!» характеризует, мягко говоря, непрофессионализм говорящего.
Третий закон (закон чечако)
Если спецификацию можно нарушить, — она будет нарушена. Новичок (чечако) способен «подвесить» любую систему.
Неквалифицированный пользователь в любом контексте всегда способен выбрать наименее подходящее действие, явно не удовлетворяющее спецификации, которая ориентирована на «разумное» поведение пользователей. Полезным практическим следствием этого закона является привлечение к этапу тестирования системы неквалифицированного пользователя — «человека с улицы».
Отладка
Что должно делать для создания корректного и устойчивого программного продукта? Как минимум, необходимо:- создать надежный код, корректность которого предусматривается с самого начала;
- отладить этот код;
- предусмотреть в нем обработку исключительных ситуаций.
Создание надежного кода
Большинство вопросов, затрагиваемых в этой лекции, в том числе и проблемы создания надежного кода, заслуживают отдельного и глубокого рассмотрения. К сожалению, придется ограничиться лишь высказыванием ряда тезисов.
Для повышения надежности нужно уменьшить сложность системы, и главное в этом процессе — это повторное использование. В идеале большая часть системы должна быть собрана из уже готовых компонентов. Объектная технология проектирования вносит свой вклад в повышение надежности кода.
Крайне важную роль в создании надежного кода играют спецификации методов класса, класса в целом, системы классов. Спецификации являются частью документации, встроенной в проект, и вообще важной его частью. Их существование облегчает не только создание корректного кода, соответствующего спецификации, но и создание системы тестов, проверяющих корректность кода. Нужно сказать, что существуют специальные инструментальные средства, поддерживающие автоматическое создание тестов на основе спецификаций. Незаменима роль спецификаций на этапе сопровождения и повторного использования компонентов. Невозможно повторно использовать компонент, если у него нет ясной и полной спецификации.
Дальше >>
< Лекция 25 || Лекция 23: 123456
Обработка ошибок — документация c-extension-tutorial
Язык программирования C не имеет исключений, как Python делает. В C все функции имеют одно возвращаемое значение, которое необходимо закодировать. возвращаемое значение, а также достоверность результата.
Глобальный индикатор исключений
CPython использует три переменные для хранения состояния текущего исключения. Эти
хранить тип текущего исключения, значение текущего исключения и
трассировка Python текущего исключения. Это как усиленный ошибка
.
Эти значения можно задать или запросить с помощью семейства функций PyErr_*
.
Распространение ошибок
Если функция C API вызывает ошибку, индикатор исключения будет установлен a будет возвращено значение, указывающее, что произошел сбой. Как потребитель функцию API, вам необходимо явно проверить возвращаемое значение этой ошибки и вернуть значение, указывающее, что ваша функция также не удалась.
ПУСТО
PyObject*
В CPython API значение NULL
никогда не допустимо для PyObject*
, поэтому он используется для сообщения о возникновении ошибки. За
пример: PyLong_FromUnsignedLong()
возвращает PyObject*
;
однако, когда память не может быть выделена, устанавливается PyExc_MemoryError
.
и возвращается NULL
.
Это наиболее распространенный индикатор ошибок, который используется для PyCFunction
с.
Логические значения
Если функция не возвращает PyObject*
, необходимо указать новый
сигнализатор ошибок. Общим случаем является функция, которая возвращает логическое значение. В С
API эти функции фактически вернут int
, а не bool
. Этот
позволяет вернуть три состояния: 1 = True
, 0 = False
и -1 =
Ошибка
.
Другое
В очень особых случаях функция должна будет явно вызвать новый дозорный
ценность. Например: PyLong_AsUnsignedLong()
возвращает значение своего
аргумент как unsigned long. Ни одно значение в домене кода не используется, поэтому оно указывает
что UNSIGNED_LONG_MAX
будет возвращено, и пользователь должен проверить
посмотрите, было ли вызвано исключение с помощью PyErr_Occurred()
.
Подсчет ссылок
Важно не забывать очищать все ресурсы или ссылки при выходе
рано для исключения. Распространенным шаблоном является использование оператора goto error
для
очистить все ваши ссылки перед возвратом НОЛЬ
.
Вызов исключений
Чтобы явно установить индикатор ошибки, мы можем использовать один из PyErr_SetString()
или PyErr_Format()
. Эти функции занимают
тип исключения и либо сообщение, либо строку формата сообщения и поднимите
данное исключение Python. После установки исключения нам нужно очистить наш
ссылки, а затем вернуть NULL
или какой-либо другой сигнал, чтобы указать
что наша функция не удалась.
Существуют также помощники для вызова общих исключений, таких как: PyErr_NoMemory()
.
Стандартные исключения
Все встроенные исключения доступны в C со схемой именования PyExc_{Name}
, где Name
— это имя, которое отображается в Python. За
пример:
PyExc_IndexError
совпадает с IndexError
из Python.
Полный список исключений можно найти здесь: https://docs.python.org/3.6/c-api/exceptions.html#standard-exceptions
Добавление обработки ошибок в
fib
Теперь, когда мы знаем об обработке и распространении исключений, давайте попробуем защитить
против неверного ввода в fib
.
Откройте fib.c
и добавьте обработку ошибок около PyLong_AsUnsignedLong()
для правильного распространения исключений.
Существует ли стандартный шаблон проектирования обработки ошибок для C?
спросил
Изменено 1 год, 5 месяцев назад
Просмотрено 834 раза
Я работаю над большим приложением C, которое я разделил на вложенные библиотеки (например, сеть, обработка сообщений, построение сообщений и т. д.)
Я пришел к шаблону, в котором функциям разрешено возвращать только ошибку коды, и все данные должны быть возвращены через предоставленные указатели. Этот шаблон хорошо зарекомендовал себя, потому что очень легко «взорвать» ошибки, генерируемые на низком уровне.
Мне любопытно, существуют ли другие стандартные шаблоны проектирования для обработки ошибок в больших программах на C?
- c
- обработка ошибок
1
Есть ошибки, и есть ошибок.
Ошибки программирования обрабатываются либо утверждениями, которые срабатывают только в режиме отладки, экономя режим выпуска от связанных с этим затрат, либо немедленным прерыванием с сообщением об ошибке. Попытка восстановления может привести к еще большему повреждению данных пользователей и, как правило, неприемлема.
Возможность внешнего вмешательства (излучение, износ вычислительной системы) требует дополнительной проверки внутренней согласованности, оставленной в версии выпуска, и использования процесса супервизора для перезапуска, если это необходимо.
Некоторые ожидаемые внешние ошибки, такие как нехватка ресурсов, отказ в необходимых ресурсах (невозможно получить достаточный доступ), ошибки ввода и ошибки одноранговых узлов, серверов и клиентов, с другой стороны, обычно должны обрабатываться корректно. Основные способы сделать это:
Сделай сам. Например, повторите попытку, подождите или попробуйте альтернативу. Часто это невозможно сделать, и это, безусловно, ухудшает контроль вызывающего абонента.
Уведомить вызывающего абонента. Пусть он справляется с этим любым подходящим способом.
- Если возвращаемое значение имеет некоторые недопустимые состояния (часто нулевой указатель, отрицательные целые числа и т.п.), используйте одно из них и при необходимости сохраните дополнительную информацию об ошибке в другом месте (см.
errno
). - Возвращает код ошибки, данные должны быть возвращены через параметры out или in-out. Может быть немного более громоздким, но может применяться равномерно.
- Возвращает структуру, объединяющую код ошибки и возвращаемые данные. Особенно популярен в функциональных языках и приобрел большую популярность благодаря Rust и другим языкам, избегающим исключений.
- Использовать исключения. Неприменимо напрямую к C, хотя взгляните на
setjmp
и longjmp. Это уже делалось раньше, например, в реализации интерпретатора Lua. - Использовать обратный вызов при возникновении ошибки. Это также часто используется для периодической информации о состоянии в длительной, возможно, неасинхронной операции, чтобы обеспечить обратную связь с пользователем. Печально известное Приложение K идет по этому пути. И одним из важных критических замечаний является использование обратного вызова, особенно то, что он даже не является локальным для потока, а не передается каждый вызов, что несколько легче переварить.
- Если возвращаемое значение имеет некоторые недопустимые состояния (часто нулевой указатель, отрицательные целые числа и т.п.), используйте одно из них и при необходимости сохраните дополнительную информацию об ошибке в другом месте (см.
2
В зависимости от вашего варианта использования может быть полезно использовать утверждения везде, где вы абсолютно на 100% уверены, что дальнейшее выполнение программы не имеет смысла или опасно.