Скачать презентацию Курс лекций по ЯП C и ООП на Скачать презентацию Курс лекций по ЯП C и ООП на

Лекция8 - Директивы препроцессора.pptx

  • Количество слайдов: 26

Курс лекций по ЯП C++ и ООП на С++ Ассистент кафедры математического моделирования и Курс лекций по ЯП C++ и ООП на С++ Ассистент кафедры математического моделирования и информационных систем, заведующий лабораторией программно аппаратных средств защиты информации Мацула Павел Владимирович (edu. plvlml@gmail. com)

Лекция 8. ДИРЕКТИВЫ ПРЕПРОЦЕССОРА Лекция 8. ДИРЕКТИВЫ ПРЕПРОЦЕССОРА

Директивы препроцессора Препроцессором называется первая фаза компилятора. Инструкции препроцес сораназываются директивами. Они должны начинаться Директивы препроцессора Препроцессором называется первая фаза компилятора. Инструкции препроцес сораназываются директивами. Они должны начинаться с символа #, перед которым в строке могут находиться только пробельные символы.

Директива #include Директива вида #include имя_файла вставляет содержимое указанного файла в ту точ куисходного Директива #include Директива вида #include имя_файла вставляет содержимое указанного файла в ту точ куисходного файла, где она записана. Имя файла может заключаться (причем пробелы до или после имени файла недопустимы) в: угловые скобки (< >); в этом случае поиск файла, если не указан полный путь, ведется в стандартных каталогах включаемых файлов; кавычки (" "); в этом случае поиск файла ведется в каталоге, содержа щемисходный файл, а затем уже в стандартных каталогах. Директива #include является простым средством обеспечения согласованно сти объявлений в различных файлах, включая в них информацию из заголовочных файлов.

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

Заголовочные файлы обычно имеют расширение. h или. hpp. Во многих реализациях заголовочные файлы стандартной Заголовочные файлы обычно имеют расширение. h или. hpp. Во многих реализациях заголовочные файлы стандартной библиотеки C++ расширения не имеют. Для каждого файла библиотеки языка С с именем имеется соответст вующий файл библиотеки C++ , в котором те же средства описываются в пространстве имен std.

Директива #define определяет макрос – средство подстановки в тексте программы. Эта директива используется для Директива #define определяет макрос – средство подстановки в тексте программы. Эта директива используется для определения: простых макросов (символических констант), все вхождения имени которых заменяются на текст подстановки: #define имя текст_подстановки сложных макросов (макросов с аргументами), которые выглядят как функции, но реализуются подстановкой их текста в текст программы: #define имя ( параметры ) текст_подстановки символов, управляющих условной компиляцией: #define имя Имена макросов рекомендуется записывать прописными буквами.

Директива #define Пример фрагмента программы: #define VERSION 4 #define BUILD 13. 666 #define VASYA Директива #define Пример фрагмента программы: #define VERSION 4 #define BUILD 13. 666 #define VASYA "Василий Иванович" cout << BUILD << endl; cout << "Ver. VERSION. BUILD by "VASYA"n"; int num. VERSION; num 4 = 4; // ошибка

Директива #define Результат работы препроцессора: cout << 13. 666 << endl; cout << Директива #define Результат работы препроцессора: cout << 13. 666 << endl; cout << "Ver. VERSION. BUILD by ""Василий Иванович""n"; int num. VERSION; Результат выполнения программы: 13. 666 Ver. VERSION. BUILD by Василий Иванович

Директива #define Некоторые сложные макросы опасны, например: #define SQUARE(a) a*a // чем опасен? y Директива #define Некоторые сложные макросы опасны, например: #define SQUARE(a) a*a // чем опасен? y = SQUARE(x+2); В результате работы препроцессора получится: y = x+2*x+2; // x + (2*x) + 2 Рекомендуется везде, где только можно, заключать в круглые скобки имена аргументов макросов, например: #define SQUARE(a) ((a)*(a))

Директива #define С помощью макросов можно до неузнаваемости изменить текст программы, например: #include <cstdio> Директива #define С помощью макросов можно до неузнаваемости изменить текст программы, например: #include #define Hello. World #define BEGIN { #define END } #define PROGRAM int main() #define WRITELN(a) puts(a); PROGRAM Hello. World BEGIN WRITELN("Hello, World") END

Директива #define Средствами макросов можно составить новую строку из двух путем использования операции препроцессора Директива #define Средствами макросов можно составить новую строку из двух путем использования операции препроцессора ##. Например: #define NAME 2(a, b) а##b int NAME 2(foo, bar)(); Превратится в: int foobar();

Директива #define Существует также операция препроцессора #, которая, будучи использована перед одним из параметров Директива #define Существует также операция препроцессора #, которая, будучи использована перед одним из параметров в теле сложного макроса, преобразует его в строковую константу. Например: #define str(x) #x cout << str(Hello. World!); Превратится в: cout << "Hello. World!";

Директива #define Благодаря использованию символа продолжения на следующую строку  аналогично строковым константам, можно Директива #define Благодаря использованию символа продолжения на следующую строку аналогично строковым константам, можно сымитировать поведение шаблона, например: #define CREATE_SWAP(T) void swap_##T(T&x, T&y){ T buf = x; x = y; y = buf; } CREATE_SWAP(bool) bool yes=true, no=false; … swap_bool(yes, no);

Предопределенные макросы В C++ определено несколько макросов, предназначенных в основном для того, чтобы выдавать Предопределенные макросы В C++ определено несколько макросов, предназначенных в основном для того, чтобы выдавать информацию о версии программы или месте возникновения ошибки: __DATE__ – содержит строку с текущей датой в формате «Мес день год» ; __FILE__ – содержит строку с полным именем текущего файла; __LINE__ – текущая строка исходного текста; __TIME__ – текущее время в формате «чч: мм: сс» ; __cplus – определен, если используется компилятор C++; конкретный текст подстановки различается в зависимости от поддерживаемой компилятором версии стандарта.

Директива #undef Для удаления определения макроса независимо от того, существовал он до этого или Директива #undef Для удаления определения макроса независимо от того, существовал он до этого или нет, предусмотрена директива #undef имя Эта директива используется редко, например: для отключения какой либо опции компилятора; чтобы защититься от нежелательных макросов, так как в точности узнать их действие на фрагмент кода бывает нелегко.

Директивы условной компиляции #if, #ifdef и #ifndef применяются для того, чтобы исключить компиляцию отдельных Директивы условной компиляции #if, #ifdef и #ifndef применяются для того, чтобы исключить компиляцию отдельных частей программы. Это бывает полез но во многих случаях: при отладке для временного закомментирования участков кода; при поддержке нескольких версий программы для различных платформ; для того, чтобы обеспечить включение заголовочного файла только один раз.

Директивы условной компиляции Формат директивы #if: #if константное_выражение … [ #elif константное_выражение …] [ Директивы условной компиляции Формат директивы #if: #if константное_выражение … [ #elif константное_выражение …] [ #else …] #endif

Директивы условной компиляции Количество директив #elif — произвольное. Исключаемые блоки кода могут со держатькак Директивы условной компиляции Количество директив #elif — произвольное. Исключаемые блоки кода могут со держатькак описания, так и исполняемые операторы. Допускается вложенность условных директив. Пример: #if VERSION == 1 #define INCFILE "ver_1. h" #elif VERSION == 2 #define INCFILE "ver_2. h" #else #define INCFILE "current. h" #endif #include INCFILE

Директивы условной компиляции В константных выражениях может использоваться проверка, определен ли макрос, с помощью Директивы условной компиляции В константных выражениях может использоваться проверка, определен ли макрос, с помощью логического выражения defined ( имя_макроса ) Наиболее часто в программах используются директивы #ifdef и #ifndef, позво ляющие управлять компиляцией в зависимости от того, определен ли с помощью директивы #define указанный в них макрос. Действие этих директив распространяется до первого #elif, #else или #endif.

Директивы условной компиляции Типичный пример применения – так называемая защита подключения (include guard): // Директивы условной компиляции Типичный пример применения – так называемая защита подключения (include guard): // Файл granny. h struct granny {}; // Файл father. h #include "granny. h" inline void father() { granny G; } // Файл mother. h #include "granny. h" inline void mother() { granny G; } // Файл child. cpp #include "father. h" #include "mother. h" father(); mother();

Директивы условной компиляции // Файл granny. h #ifndef GRANNY_H_ #define GRANNY_H_ struct granny {}; Директивы условной компиляции // Файл granny. h #ifndef GRANNY_H_ #define GRANNY_H_ struct granny {}; #endif // Файл father. h // Файл mother. h #include "granny. h" inline void father() inline void mother() { granny G; } // Файл child. cpp #include "father. h" #include "mother. h" father(); mother();

Директива #pragma позволяет использовать специфичные для конкретных реализаций компилятора директивы в форме #pragma имя_директивы Директива #pragma позволяет использовать специфичные для конкретных реализаций компилятора директивы в форме #pragma имя_директивы Если используемый компилятор не поддерживает встретившуюся в тексте директиву #pragma, она игнорируется.

Директива #pragma once — нестандартная, но широко распространенная директива для контроля за тем, чтобы Директива #pragma once — нестандартная, но широко распространенная директива для контроля за тем, чтобы конкретный заголовочный файл подключался строго один раз. Она исключает риск коллизии имен макросов защиты подключения, но может привести к ошибке при работе с символьными ссылками в Unix подобной среде. Предыдущий пример можно видоизменить так: // Файл "granny. h" #pragma once struct granny {};

Директива #line позволяет переопределить имя текущего файла и номер следующей строки – например, для Директива #line позволяет переопределить имя текущего файла и номер следующей строки – например, для последующего вывода предупреждений или сообщений об ошибке, а также значений предопределенных макросов. Ее формат следующий: #line номер_строки [ "имя_файла" ] Например: #line 776 "jack. pot" cout << __FILE__ << ': '; cout << __LINE__; Результат: jack. pot: 777

Директива #error прерывает процесс компиляции, как только ее обнаруживает препроцессор, выдавая сообщение, которое можно Директива #error прерывает процесс компиляции, как только ее обнаруживает препроцессор, выдавая сообщение, которое можно передать ей как параметр, например: #ifndef __cplus #error A C++ compiler is required! #endif