Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2014_2015 / LECT14_2015.pptx
Скачиваний:
9
Добавлен:
27.12.2015
Размер:
178.88 Кб
Скачать

Директивы препроцессора Препроцессор - обязательный компонент интегрированной среды подготовки программ или компилятора С++ (С). Просматривает программу до компилятора и заменяет символические аббревиатуры в программе на соответствующие макроопределения, отыскивает другие файлы, подключает их, а также может изменять условия компиляции. Препроцессорная обработка включает несколько стадий, выполняемых последовательно. Конкретная реализация может объединять несколько стадий, но результат должен быть таким, как если бы они выполнялись в следующем порядке:

1.Все системно-зависимые обозначения перекодируются в стандартные коды.

2.Каждая пара из символов '\' и "конец строки" вместе с пробелами между ними убираются, и тем самым следующая строка исходного текста присоединяется к строке, в которой находилась эта пара символов.

3.В тексте распознаются директивы и лексемы препроцессора, а каждый комментарий заменяется одним символом пустого промежутка.

4.Выполняются директивы препроцессора и производятся макроподстановки.

5.ESC-последовательности в символьных константах и символьных строках заменяются на их эквиваленты.

6.Смежные символьные строки конкатинируются, то есть соединяются в одну строку.

7.Каждая препроцессорная лексема преобразуется в текст на языке С (С++).

Любая строка с ведущим символом # рассмат-ривается как директива препроцессора, если только # не входит в строковый литерал, символьную конс-танту или комментарий. Ведущему символу # может предшествовать, либо следовать за ним, пробельные символы (за исключением символа новой строки). Если непосредственно перед концом строки поставить символ

ESC-последовательности – специальные символьные комбинации, которые представляют пробельные символы и неграфические символы в строках и символьных константах.

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

ESC-последовательность состоит из наклонной черты влево, за которой следует буква, знаки пунктуации ' " \ или комбинация цифр.

\n Новая строка

\' Одиночная кавычка

\t Горизонтальная

\" Двойная кавычка

табуляция

\\ Наклонная черта влево

\v Вертикальная

\ddd ASCII символ в восьми-

табуляция

ричном представлении

\b Пробел

\xdd ASCII символ в шестнад-

\r Возврат каретки

цатиричном представлении

\f Новая страница

 

Препроцессорные лексемы или лексемы препроцессора - символьные константы, имена включаемых файлов, идентификаторы, знаки операций, препроцессорные числа, знаки препинания, строковые константы и любые символы, отличные от пробела.

При выполнении стадии обработки директив препроцессора возможны следующие действия:

замена идентификаторов заранее подготовленными последовательностями символов;

включение в программу текстов из указанных файлов;

исключение из программы отдельных частей ее текста, условная компиляция;

макроподстановка, то есть замена обозначения параметризованным текстом, формируемым препроцессором с учетом конкретных аргументов.

Директивы препроцессора обычно помещаются в начало исходного кода, но допустимы в любой точке программы.

Препроцессор обеспечивает мощные средства и гибкость, т.к. позволяет:

-Определение макросов, которые служат для снижения трудоемкости программирования и улучшении читаемости кода. Некоторые макросы позволяют избежать затрат на вызов функций.

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

-Установку условной компиляции для улучшения мобильности получаемых кодов и для целей отладки.

Пустая директива # - состоит из строки, в которой содержится единственный символ #. Эта директива всегда игнорируется препроцессором.

Директива #include включает в текст программы содержимое указанного файла. Эта директива имеет две формы:

#include " имя_файла " #include <имя_файла>

Имя файла должно соответствовать соглашениям с операционной системой и может состоять либо только из имени файла, либо из имени файла с указанием маршрута до него.

Если имя файла указано в кавычках, то поиск файла осуществляется в соответствии с заданным маршрутом, а при его отсутствии - в текущем каталоге. Если имя файла задано в угловых скобках, то поиск файла производится в стандартных директориях операционной системы, задаваемых в

файле AUTOEXEC командой PATH

Директива #define служит для замены часто использующихся констант, ключевых слов, операторов или выражений некоторыми идентификаторами. Идентификаторы, заменяю-щие текстовые или числовые константы - именованные константы. Идентификаторы, заменяющие фрагменты программ - причем макроопределения могут имакроопределения,меть аргументы.

Директива #define имеет 2 синтаксические формы: #define идентификатор текст

#define идентификатор(список параметров) текст Эта директива заменяет все последующие вхождения идентификатора на текст. Такой процесс называется макроподстановкой. Текст может представлять собой любой фрагмент программы на С++, а также может и отсутствовать. В последнем случае все экземпляры идентификатора удаляются из программы.

#define HI "Good day!" #define empty #define NIL " "

...

puts(HI); /* расширяется в: puts("Good day!"); */ puts(NIL); /* расширяется в: puts(" "); */ puts("empty"); /* расширения empty не происходит ! */

/* расширение empty не будет выполнено и в комментариях! */ После расширения каждого конкретного макроса

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

#define GETSTD #include <stdio.h>

...

GETSTD /* ошибка компиляции */

GETSTD будет расширен в #include <stdio.h>. Однако, препроцессор не станет сам обрабатывать эту вполне директиву, а передаст ее в таком виде компилятору. Компилятор воспримет #include <stdio.h> как недопустимый ввод. Макрос не может быть расширен во время собственного расширения выражения типа #define A A недо-пустимы вследствие неопределенности результата.

Директива #undef используется для отмены действия директивы #define. Синтаксис этой директивы следующий:

#undef идентификатор

Директива отменяет действие текущего определения #define для указанного идентификатора. Не является ошибкой использование директивы #undef для иден- тификатора, который не был определен директивой

Состояние определенности и неопределенности является важным свойством идентификатора, независимо от его фактического определения.

Условные директивы препроцессора #ifdef и #ifndef - для проверки того, является ли идентификатор в текущий момент определенным, или нет гибкий механизм управления многими аспектами компиляции.

После того, как идентификатор макроса стал неопределенным, он может быть далее переопределен директивой #define, с использованием той же самой или другой последовательности лексем.

#define BLOCK_SIZE 512

...

buff = BLOCK_SIZE*blks; /* расширяется в: 512*blks */

...

#undef BLOCK_SIZE

/* использование BLOCK_SIZE теперь невозможно - это

"неизвестный" препроцессору идентификатор */

...

#define BLOCK_SIZE 128 /* переопределение размера блока */

...

buf = BLOCK_SIZE*blks; /* расширяется в: 128*blks */

...

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

#ifndef BLOCK_SIZE #define BLOCK_SIZE 512 #endif

Если идентификатор BLOCK_SIZE в текущий момент определен, то средняя строка не обрабатывается препроцессором; в противном же случае выполняется

Соседние файлы в папке 2014_2015