- •3.В тексте распознаются директивы и лексемы препроцессора, а каждый комментарий заменяется одним символом
- •ESC-последовательности – специальные символьные комбинации, которые представляют пробельные символы и неграфические символы в
- •Препроцессорные лексемы или лексемы препроцессора - символьные константы, имена включаемых файлов, идентификаторы, знаки
- •Директивы препроцессора обычно помещаются в начало исходного кода, но допустимы в любой точке
- •Состояние определенности и неопределенности является важным свойством идентификатора, независимо от его фактического определения.
- •!!! директива препроцессора не должна заканчиваться точкой с запятой (;). Любые символы, найденные
- •Вызов макроса приводит к двум типам замены:
- •Пример:
- •Сравните CUBE и cube:
- •Условная компиляция - исходный файл можно компили- ровать не целиком, а частями, используя
- •Макроопределения могут изменяться при различных действиях компиляции по неким причинам.
- •Можно - один и тот же исходный файл скомпилировать в две разные программы
- •!!! все знаки являются важными, за исключением пробелов, расположенных в начале и в
- •часть-группы:
- •управляющая-строка:
Директивы препроцессора Препроцессор - обязательный компонент интегрированной среды подготовки программ или компилятора С++ (С). Просматривает программу до компилятора и заменяет символические аббревиатуры в программе на соответствующие макроопределения, отыскивает другие файлы, подключает их, а также может изменять условия компиляции. Препроцессорная обработка включает несколько стадий, выполняемых последовательно. Конкретная реализация может объединять несколько стадий, но результат должен быть таким, как если бы они выполнялись в следующем порядке:
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 в текущий момент определен, то средняя строка не обрабатывается препроцессором; в противном же случае выполняется