Условная компиляция
Директивы ветвлений Условная компиляция обеспечивается в языке Си следующим набором директив, которые управляют не компиляцией, а препроцессорной обработкой текста:
Формат: #if целочисленное_константное_выражение #ifdef идентификатор #ifndef идентификатор #else #endif #elif Первые три директивы выполняют проверку условий, две следующие - позволяют определить диапазон действия проверяемого условия. (Директиву #elif рассмотрим несколько позже.) Общая структура применения директив условной компиляции такова: #if… текст_1 #else текст_2 #endif Конструкция #else текст _2 необязательна. Текст_1 включается в компилируемый текст только при истинности проверяемого условия (обозначено многоточием после #if). Если условие ложно, то при наличии директивы #else на компиляцию передается текст_2. Если директива #else и текст_2 отсутствуют, то весь текст от #if до #endif при ложном условии опускается. Различие между формами команд #if состоит в следующем. В первой из перечисленных директив #if целочисленное константное выражение проверяется значение константного выражения, в которое могут входить целые константы и идентификаторы. Идентификаторы могут быть определены на препроцессорном уровне, и тогда их значение определяется подстановками. В противном случае считается, что идентификаторы имеют нулевые значения. Если константное выражение отлично от нуля, то считается, что проверяемое условие истинно. Пример 10.12 В результате выполнения директив: 5+4 текст_1 #endif текст_1 всегда будет включен в компилируемую программу.
В директиве #ifdef идентификатор проверяется, определен ли с помощью директивы #define к текущему моменту идентификатор, помещенный после #ifdef. Если идентификатор определен, т.е. является препроцессорным, то текст_1 используется компилятором. В директиве #ifndef идентификатор проверяется обратное условие – истинным считается неопределенность идентификатора, т.е. тот случай, когда идентификатор не был использован в команде #define или его определение было отменено командой #undef.
Условную компиляцию удобно применять при отладке программ для включения или исключения средств вывода контрольных сообщений. Пример 10.13 #define DEBUG #ifdef DEBUG printf (“ Отладочная печать “); #endif
Таких вызовов функции printf(), появляющихся в программе в зависимости от определенности идентификатора DEBUG, может быть несколько, и, убрав либо поместив в скобки комментария /*...*/ директиву #define DEBUG, сразу же отключаем все отладочные средства. Файлы, предназначенные для препроцессорного включения в программу, обычно снабжают защитой от повторного включения. Такое повторное включение может произойти, если несколько файлов, в каждом из которых в свою очередь запланировано препроцессорное включение одного и того же файла, объединяются в общий текст программы. Например, такими средствами защиты снабжены все заголовочные файлы стандартной библиотеки.
Пример 10.14 Схема защиты от повторного включения может быть такой: /* Файл с именем filename */ /* Проверка определенности _FILE_NAME */ #ifndef _FILE_NAME.../* Включаемый текст файла filename */ /* Определение _FILE_NAME */ #define _FILE_NAME #endif Здесь _FILE_NAME – зарезервированный для файла filename препроцессорный идентификатор, который желательно не использовать в других текстах программы. Для организации мультиветвлений (аналог операции switch) во время обработки препроцессором исходного текста программы введена директива #elif целочисленное константное выражение
Требования к целочисленному константному выражению те же, что и в директиве #if. Структура исходного текста с применением этой директивы такова: Пример 10.15 #if условие тeкcт для if #elif выражение_1 текст_1 #elif выражение _2 текст_2 #else текст для случая els #endif
Препроцессор проверяет вначале условие в директиве #if. Если оно ложно (равно 0), – вычисляется выражение_1; если при этом оказывается, что и значением выражения_1 также является 0, – вычисляется выражение_2, и т.д. Если все выражения ложны (равны 0), то в компилируемый текст включается текст_для_случая_else. В противном случае, т.е. при появлении хотя бы одного истинного выражения (в #if или в #elif), начинает обрабатываться текст, расположенный непосредственно за этой директивой, а все остальные директивы не рассматриваются. Таким образом, препроцессор обрабатывает всегда только один из участков текста, выделенных директивами условной компиляции.
|