Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 10 лет назад пользователемДиана Яворовская
1 Основы информатики Лекция. Директивы. Исключения Заикин Олег Сергеевич
2 Препроцессор С / С ++ Препроцессор С/С++ программный инструмент, изменяющий код программы для последующей компиляции и сборки, используемый в языках программирования Си и его потомка - C++. Этот препроцессор обеспечивает использование стандартного набора возможностей: Включение файла #include Макроподстановки #define Условная компиляция #if, #ifdef, #elif, #else, #endif
3 Препроцессор С / С ++ Препроцессор языка Си низкоуровневый, лексический препроцессор, потому что он требует только лексического анализа, то есть он обрабатывает только исходный текст перед компиляцией, выполняя простую замену лексем и специальных символов заданными последовательностями символов, в соответствии с правилами, установленными пользователями.
4 Директивы препроцессора Директивой препроцессора называется строка в исходном коде, которая начинается с символа # и следующего за ним ключевого слова препроцессора. Cписок ключевых слов: define задаёт макроопределение (макрос) или символическую константу undef отменяет предыдущее определение include вставляет текст из указанного файла if осуществляет условную компиляцию при истинности константного выражения
5 Директивы препроцессора ifdef осуществляет условную компиляцию при определённости символической константы выражения ifndef осуществляет условную компиляцию при неопределённости символической константы else ветка условной компиляции при ложности выражения elif ветка условной компиляции, образуемая слиянием else и if endif конец ветки условной компиляции
6 Директива #define, макросы Макросы в языке Си преимущественно используются для определения небольших фрагментов кода. Во время обработки кода препроцессором, каждый макрос заменяется соответствующим ему определением. Например #define _WIN32 определяет макрос _WIN32 Теперь проверка #ifdef _WIN32 вернет истину
7 Директива #define, макросы Если макрос имеет параметры, то они указываются в теле макроса; таким образом, макросы языка Си могут походить на Си-функции. Распространенная причина использования избежание накладных расходов при вызове функции в простейших случаях, когда небольшого кода, вызываемого функцией, достаточно для ощутимого снижения производительности.
8 Например #define max(a,b) ((a) > (b) ? (a) : (b)) определяет макрос max, использующий два аргумента a и b. Этот макрос можно вызывать как любую Си-функцию, используя схожий синтаксис. То есть, после обработки препроцессором, z = max(x,y); становится z = ((x) > (y) ? (x) : (y)); Директива #define, макросы
9 Кроме пользовательских макросов препроцессор имеет встроенные макросы которые не требуют объявления: __LINE__ - заменяется на номер строки, может быть переопределен директивой #line, чаще всего используется для создания отладочной информации __FILE__ - заменяется на имя файла, так же может быть переопределено с помощью директивы #line __DATE__ - заменяется на текущую дату (на момент компиляции, а точнее обработки препроцессором) __TIME__ - заменяется на текущее время Предопределенные макросы
10 Директива #include Препроцессор Си, встречая следующие директивы: #include "..." или #include полностью копирует содержимое указанного файла в файл, в котором указана эта директива, в месте вызова директивы. Эти файлы обычно содержат классы и типы данных, которые должны быть подключены перед их использованием; таким образом, директива #include обычно указывается в начале (заголовке) файла. По этой причине подключаемые файлы и называются заголовочными.
11 Препроцессор языка Си предоставляет возможность компиляции с условиями. Это допускает возможность существования различных версий одного кода. Обычно, такой подход используется для настройки программы под платформу компилятора, состояние ( отлаживаемый код может быть выделен в результирующем коде ), или возможность проверки подключения файла строго один раз. Условная компиляция
12 Допустим мы пишем программу, которая содержит отладочный вывод в файл. Этот вывод имеет смысл включать только тогда, когда разработчик программы занимается её отладкой. Версия, которую программист отдаёт пользователю, этих выводов не должна содержать. Для этого, например, можно в программе завести переменную и ставить все печати под условие. Условная компиляция
13 const int debug = 1;... void func (void) { if (debug) std::cout
14 Но если программа состоит из нескольких исходных файлов, то такой фокус не пройдёт, потому как переменная должна быть определена только в одном модуле, а остальные модули не будут видеть значения переменной, а потому не смогут удалить мёртвый код. При этом вызов cout в коде программы останется, хоть и будет стоять под условием, которое никогда не будет равно true. По большому счёту и это тоже терпимо, т. к. десяток или сотня вызовов cout принципиально размер бинарного фала не увеличат ( т. е. увеличение будет составлять единицы процентов, но не в разы ). Хуже обстоит дело, когда мы вызываем не cout, а какую - то " нашу " функцию, которая нужна только для отладочных печатей. Условная компиляция
15 Чтобы избежать этих проблем, ненужный код надо физически вырезать из программы. И для этих целей удобно использовать директиву условной компиляции #if #define DEBUG 1 #if DEBUG == 1 void debug_print (...) {... } #endif void func (void) { #if DEBUG == 1 debug_print (...); #endif... } Условная компиляция
16 Если DEBUG == 1, то после препроцессора будет такой код void debug_print (...) {... } void func (void) { debug_print (...);... } Теперь если мы значение макроса DEBUG поменяем на 0, то ненужный нам текст физически вырежется и в компиляцию в принципе не попадает void func (void) {... } Условная компиляция
17 В случае работы с несколькими файлами определение макроса DEBUG следует поместить в один из файлов *.h, который подключается во всех исходных файлах. Работа с макросом в данном случае (да и не только в данном) требует аккуратности. Что важно в данном случае - управление наличием или отсутствием кода осуществляется путём замены единственного символа и не требует каких-то постоянных усилий по закомментированию и раскомментированию кода. В MS Visual Studio есть макрос _DEBUG Условная компиляция
18 В каждый заголовочный файл нужно добавлять стражи включения, чтобы содержимое файла не добавлялось более одного раза. Пример. fname.h: #ifndef FNAME_H #define FNAME_H … // содержимое заголовочного файла #endif Стражи включения
19 // file1. cpp #include header.h #include fname.h … // header.h #include fname.h … В файле file1. cpp после первого подключения файла fname.h станет определена константа FNAME_H, и второе включение не произойдет. Стражи включения
20 Обработка исключений Исключительная ситуация, или исключение это возникновение непредвиденного или аварийного события, которое может порождаться некорректным использованием аппаратуры. Синхронные исключения могут возникнуть только в определённых, заранее известных точках программы. Примеры : ошибка чтения файла, попытка выделения памяти при ее нехватке.
21 Обработка исключений Асинхронные исключения могут возникать в любой момент времени. Примеры : аварийный отказ питания, поступление новых данных. Исключения позволяют логически разделить вычислительный процесс на две части : обнаружение аварийной ситуации ; ее обработка.
22 Возможные действия при ошибке прервать выполнение программы ; возвратить значение, означающее « ошибка »; вывести сообщение об ошибке в поток cerr и вернуть вызывающей программе некоторое приемлемое значение, которое позволит ей продолжать работу. обработать исключение
23 Поток cerr Выходной поток cerr нужен для отправки сообщений на стандартное устройство ошибок. Если вывод сообщений программы перенаправлен в файл, то сообщения потока cerr все равно будут показаны в консоли. Пример. if (x < 0) { cerr out.txt
24 Механизм обработки исключений Функция, в которой возникла ошибка, генерирует исключение ( используется ключевое слово throw с параметром - константой, переменной или объектом ) Отыскивается соответствующий обработчик и ему передается управление Если обработчик не найден, вызывается стандартная функция terminate, которая вызывает функцию abort
25 Синтаксис исключений try ( пытаться ) - начало блока исключений. throw ( бросить ) - ключевое слово, " создающее " исключение. catch ( поймать ) - начало блока, " ловящего " исключение.
26 Синтаксис исключений Контролируемый блок : try{... } Генерация исключения : throw [ выражение ]; Обработчики исключений : catch( тип имя ){... } catch( тип ){... } catch(...){... }
27 Перехват исключений Когда с помощью throw генерируется исключение, функции исполнительной библиотеки : 1. создают копию параметра throw в виде статического объекта, который существует до тех пор, пока исключение не будет обработано ; 2. в поисках подходящего обработчика раскручивают стек, вызывая деструкторы локальных объектов, выходящих из области действия ; 3. передают объект и управление обработчику, имеющему параметр, совместимый по типу с этим объектом.
28 Подходящий обработчик : тот же, что и в параметре catch; является производным от указанного в параметре catch ( если наследование производилось с ключом доступа public); является указателем, который может быть преобразован по стандартным правилам преобразования указателей к типу указателя в параметре catch.
29 ©Павловская Т.А. (СПбГУ ИТМО) Пример 1 class A { public: A() { cout
30 Пример 2 #include class Hello{ public: Hello(){cout
31 int main() { try{ cout
32 Результаты выполнения программы : Входим в try- блок Hello! Генерируем исключение Bye! Обработчик const char * - Ошибка при открытии файла
33 Неперехваченные исключения Если исключение сгенерировано, но не перехвачено, вызывается стандартная функция std::terminate(). Функция terminate() будет также вызвана, если механизм обработки исключения обнаружит, что стек разрушен, или если деструктор, вызванный во время раскрутки стека, пытается завершить свою работу при помощи исключения. По умолчанию terminate() вызывает функцию abort().
34 Стандартные исключения bad_alloc ошибка при динамическом распределении памяти с помощью new; bad_cast неправильное использование оператора dynamic_cast bad_typeid операция typeid не может определить тип операнда ; bad_exception при вызове функции произошло неожидаемое исключение ; length_error попытка создания объекта, большего, чем максимальный размер для данного типа ;
35 domain_error нарушение внутренних условий перед выполнением действия ; out_of_range попытка вызова функции с параметром, не входящим в допустимые значения ; invalid_argument попытка вызова функции с неверным параметром ; range_error неправильный результат вычислений при выполнении ; overflow_error арифметическое переполнение ; underflow_error исчезновение порядка. Стандартные исключения
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.