Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Директивы препроцессора.doc
Скачиваний:
7
Добавлен:
20.07.2019
Размер:
206.34 Кб
Скачать

Цепочка подстановок

В рассмотренных выше примерах строка замещения представляла собой некоторую символьную константу. В более общем случае строка замещения является выражением. В качестве отдельной лексемы в ней может содержаться макрос, ранее определенный другой директивой #define. Таким образом, препроцессор выполняет цепочку последовательных подстано­вок.

Пример: Определение диапазона возможных значений любой целой переменной типа int.

#include <limits.h>

#define RANGE ((INT_MAX) - (INT_MIN) +1)

/*RANGE - диапазон значений для int */

int RANGE_T = RANGE/8;

При работе препроцессора сначала выполняется директива #include <limits.h> - в текст программы вставляется текст из файла limits.h (кратко директива #include уже была рассмотрена в лекции 12).

В данном файле определены константы INT_MAX, INT_MIN, указывающие предельное максимальное и минимальное значение целых величин соответственно. Таким образом, программа принимает вид:

#define INT_MAX 32767

#define INT_MIN -32768

#define RANGE ((INT_MAX) - (INT_MIN) + 1)

/*RANGE - диапазон значений для int*/

int RANGE_T = RANGE/8;

Директива #include в тексте программы заменилась на соответствующий текст (значения констант могут различаться в зависимости от разрядности ЭВМ).

Далее препроцессор выполняет подстановки в соответствии с двумя первыми директивами #define и программа принимает вид:

#define RANGE ((32767) - (-32768) + 1)

/*RANGE - диапазон Значений для int*/

int RANGE_T = RANGE/8;

В результате выполнения подстановок изменилась строка замещения макроса RANGE в последней директиве #define. После выполнения данной директивы текст программы примет вид:

/*RANGE - диапазон значений для int*/

int RANGE_T = ((32767)-(-32768)+1)/8;

Теперь все директивы #define удалены из текста.

Подстановка строки замещения вместо имени макроса RANGE была выполнена в выражении RANGE/8. Согласно рассмотренным ранее ограничениям не произошло подстановки внутри комментария, а также остался без изменений идентификатор RANGE_T.

Параметризованное макороопределение

Использование макроопределения без параметров имеет существенный недостаток - строка замещения фиксиро­вана. Большие возможности предоставляет макроопределение с параметрами:

#define идентификатор(параметры) строка_замещения

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

Для макровызова использу­ется конструкция вида:

идентификатор (аргументы)

аргументы – список препроцессорных лексем, разделенных запятыми.

Пример:

Макроопределение

#define MAX(x,y) ((x) < (y) ? (x) : (y))

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

Аргументы макровызова используются при макроподстановке. Например, макровызов

у = MAX(suml, sum2);

он будет заменен на

у = ((suml)>(sum2)?(suml):(sum2));

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

Пример:

Если определен макрос

#define sqr(x) (x*x)

то макровызов sqr(y+l) будет заменен выражением sqr(у+1*у+1).

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

Препроцессорные операции в строке замещения

В строке замещения могут быть использованы операции # и ##.

Операция # помещается перед параметром. При макроподстановке аргумент, замещающий данный параметр, заклю­чался в двойные кавычки.

Пример:

Если определен макрос

#define print(A) printf(#A“=%f”, А)

то макровызов

print (sin (a/2));

будет заменен оператором

printf (“sin(a/2)”“=%f”, sin (a/2));

Последовательность операторов

double а=3.14159;

print (sin (a/2));

выведет на экран текст

sin(a/2)=1.0

Операция ## помещается между двумя лексемами строки замещения, и осуществляет их конкатенацию (соединение).

Пример:

Определены три макроса с одинаковым списком параметров и одинаковы­ми аргументами. Отличает только строка замещения.

#define zero(a, b, с, d) a (bcd)

#define one(a, b, c, d) a (b с d)

#define two(a, b, c, d) a (b##c##d)

Макровызов: Результат макроподстановки:

zero(sin, x, +, у) sin(bсd)

one(sin, x, +, у) sin(x + у)

two(sin, x, +, y) sin(x+y)

В строке замещения макроса zero( ) последовательность “bсd” воспринимается как отдельный идентификатор. Замена символов b, с, d в составе идентификатора bсd аргуметами, соответствующими параметрам b, с, d не вы­полняется.

В строке замещения макроса one( ) символы b, с, d воспринимаются как три отдельных параметра, т.к. они отделены друг от друга пробелами. После макроподстановки пробелы сохраняются.

В строке замещения для макроса two( ) между параметрами b и с, с и d использована операция ##. Это позволяет после макроподстановки получить запись аргументов без пробелов между ними.