В рассмотренных выше примерах строка замещения представляла собой некоторую символьную константу. В более общем случае строка замещения является выражением. В качестве отдельной лексемы в ней может содержаться макрос, ранее определенный другой директивой #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.