Студопедия Главная Случайная страница Задать вопрос

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

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





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

 

Пример 10.2

#include <limits.h>

#define RANGE ((INT_MAX) – < INT_MIN)+1)

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

int RANGE_T = RANGE/8; ………….

 

Препроцессор последовательно просматривает текст и, обнаружив директиву #include <limits.h>, вставляет текст из файла limits.h. Там определены константы 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 исчезла из программы, но ее заменил соответствующий текст. Обнаружив в тексте (добытом из файла limits.h) директивы define..., препроцессор выполняет соответствующие подстановки, и программа принимает следующий вид:

 

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

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

int RANGE_T = RANGE/8;

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

 

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

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

 

Теперь все директивы #define удалены из текста. Получен текст, пригодный для компиляции, т.е. создана «единица трансляции». Подстановка строки замещения вместо идентификатора RANGE выполнена в выражении RANGE/8, однако внутри комментария идентификатор RANGE остался без изменений и не изменился идентификатор RANGE_Т.

Этот пример иллюстрирует выполнение «цепочки» подстановок и ограничения на замены: замены не выполняются внутри комментариев, внутри строковых констант, внутри символьных констант и внутри идентификаторов (не может измениться часть идентификатора). Например, RANGE_T остался без изменений.

Если строка замещения оказывается слишком длинной, то ее можно продолжить в следующей строке текста. Для этого в конце продолжаемой строки помещается символ ‘\’. В ходе одной из стадий препроцессорной обработки этот символ вместе с последующим символом конца строки будет удален из текста программы.

Пример 10.3

#define STRING "\n Game Over! – Игра закончена!"

printf(STRING);

На экран будет выведено:

Game Over! – Игра закончена!

 

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

 

Пример 10.4

Исходный текст Результат препроцессорной обработки

#define К 40

void main( ) void main ( )

{ {

int M[K][K] ; int M[40][40] ;

float A[2*K+1], float A[2*40+l] ,

float B[K+3][K-3] float В[40+3][40-3];

…….. ……..

 

При таком описании очень легко изменять предельные размеры сразу всех массивов, изменив только одну константу (строку замещения) в директиве #define. Предусмотренные директивой #define препроцессорные. замены не выполняются внутри строк, символьных констант и комментариев, т.е. не распространяются на тексты, ограниченные кавычками (“), апострофами (‘) и разделителями (/*,. */). В то же время строка замещения может содержать перечисленные ограничители, например, при замене препроцессорного идентификатора STRING.

Если в программе нужно часто печатать или выводить на экран дисплея значение какой-либо переменной и, кроме того, снабжать эту печать одним и тем же пояснительным текстом, то удобно ввести сокращенное обозначение оператора печати, например:

 

Пример 10.5

#define PK printf(“\n Номер элемента=%d.”,N) ;

 

После этой директивы использование в программе оператора РК; будет эквивалентно (по результату) оператору из строки замещения. Например, последовательность операторов

int N = 4; РК;

приведет к выводу такого текста:

Номер элемента=4.

 

Если в строку замещения входит идентификатор, определенный в другой команде #define, то в строке замещения выполняется следующая замена (цепочка подстановок). Например, программа, содержащая команды:

Пример 10.6

#define К 50

#define PE printf (“\п Число элементов K=%d”,K);

…….

РЕ;

выведет на экран такой текст:

Число элементов К=50

Идентификатор К внутри строки замещения, обрамленной кавычками, не заменяется на 50.

 

Строку замещения, связанную с конкретным препроцессорным идентификатором, можно сменить, приписав уже определенному идентификатору новое значение другой командой #define:

 

Пример 10.7

#define M 16 /* Идентификатор М определен как 16 */

#define M ‘С’ /* М определен как символьная константа ‘С’ */

#define M “С” /* М определен как символьная строка, в которой есть два элемента ‘С’ и ‘\0’ */

 

Однако при таких сменах значений препроцессорного идентификатора некоторые компиляторы C++ выдают предупреждающее сообщение на каждую следующую директиву #define:

 

Warning ..: Redefinition of ‘M’ is not identical

Замены в тексте можно отменять с помощью команды

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

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

#define M 16

#undef M

#define M ’С’

#undef M

#define M ”С”

 

Директиву #undef удобно использовать при разработке больших программ, когда они собираются из отдельных «кусков текста», написанных в разное время или разными программистами. В этом случае могут встретиться одинаковые обозначения разных объектов. Чтобы не изменять исходных файлов, включаемый текст можно «обрамлять» подходящими директивами #define, #undef и тем самым устранять возможные ошибки.

 

Пример 10.8

…….

А = 10; / Основной текст*/

…….

#define A X

…….

А = 5; / Включенный текст */

………..

#undef A

………..

В = А; / Основной текст */

……….

 

При выполнении программы переменная В примет значение 10, несмотря на наличие оператора присваивания А = 5 во включенном тексте.






Дата добавления: 2014-11-10; просмотров: 177. Нарушение авторских прав

Studopedia.info - Студопедия - 2014-2017 год . (0.011 сек.) русская версия | украинская версия