- •Стадии препроцессорной обработки
- •Макроопределение без параметров
- •Пример:
- •Пример:
- •Пример:
- •Цепочка подстановок
- •Сравнение макросов и функций
- •Пример:
- •Пример:
- •Пример:
- •Int II, jj, ll; // целые внешние переменные
- •Условная компиляция
- •Пример:
- •Пример:
- •Пример:
- •Вспомогательные директивы
- •Пример:
- •Void main ( ) // строка 2
- •Пример:
Макроопределение без параметров
Простейшее макроопределение с помощью директивы #define имеет вид:
#define идентификатор строка_замещения
С помощью такого макроопределения задается препроцессорный макрос без параметров. Идентификатор задает имя макроса. Данное имя используется для обращения к макросу. В результате работы препроцессора все вхождения указанного идентификатора в тексте программы заменяются на символьную последовательность, задаваемую строкой замещения. Символы пробелов, помещенные в начале и в конце строки замещения, в подстановке не используются. Данный процесс называется макровызовом (вызовом макроса).
Директива #define может указываться в любом месте текста программы, а ее действие в обычном случае распространяется от точки размещения до конца текста.
Пример:
Исходный текст Результат препроцессорной обработки
#define begin {
#define end }
void main( ) void main( )
begin {
операторы операторы
end }
В исходном тексте программы в качестве операторных скобок используются идентификаторы begin, end. Препроцессор заменяет все вхождения данных идентификаторов стандартными скобками { и }. Выполненные директивы #define из текста исключаются.
Если строка замещения является слишком длинной, она может быть перенесена на следующую строку. Это можно осуществить, поместив символ ‘\’ в конце продолжаемой строки. В ходе второй стадии препроцессорной обработки этот символ вместе с последующим символом конца строки будет удален из текста программы.
Пример:
#define STRING "\n Game Over! - \
Игра закончена!"
printf (STRING);
На экран будет выведено:
Game Over! - Игра закончена!
В примере имя макроса записано прописными буквами. Данный прием удобен тем, что позволяет зрительно отличать имена макросов от имен переменных и функций.
Действие макроподстановок, выполняемых согласно с директивой #define, имеет ряд ограничений. Замены не выполняются внутри:
комментариев (строк, ограниченных символами /* и */ или записанных после знака //),
символьных констант (символов, ограниченных апострофами '),
строковых констант (строк, ограниченных двойными кавычками "),
внутри идентификаторов (часть идентификатора не может быть заменена).
Пример:
#define n 24
char с = '\n'; // c - cимвольная константа, \n - escape-последовательность
c = ‘n’ > ‘\n’?'\n':'\n'
int k = n;
В ходе препроцессорной обработки данного текста замена идентификатора n на число 24 будет выполнена только один раз в последнем определении, которое примет вид:
int k=24;
Все остальные вхождения символа n в составе строковых констант препроцессором будут проигнорированы.
В строке замещения символы /*, */, //, ', " могут присутствовать (например, как в строке замещения макроса STRING).
Строку замещения, связанную с конкретным препроцессорным идентификатором, можно сменить, приписав уже определенному идентификатору новое значение другой командой #define:
#define M 16 // идентификатор М определен как 16
#define M ‘С’ // идентификатор М определен как символьная константа ‘С’
#define M “С”
/* идентификатор М определен как строковая константа */
/* с двумя элементами: ‘С’и ‘\0’ */
Однако при таких сменах значений препроцессорного идентификатора компилятор выдает предупреждающее сообщение на каждую следующую директиву #define:
Warning ..: Redefinition of 'M' is not identical