Директивы #if, #ifdef, #ifndef, #else, #endif, #elifназывают директивами условной компиляции. Они позволяют организовать условную (в зависимости от результата выполнения некоторого условия) препроцессорную обработку текста программы. Таким образом, из последующего процесса компиляции можно исключить часть текста программы. Поэтому перечисленные директивы называются директивами условной компиляции, хотя, как и все директивы препроцессора, они управляют препроцессорной обработкой текста программыдо ее компиляции.
Общая структура их применения имеет следующий формат:
#if | #ifdef | #ifndef условие
текст_1
[#else
текст_2]
#endif
Директива #endif указывает окончание действия директивы #if (#ifdef, #ifndef).
Текст_1включается в компилируемый текст только при истинности проверяемого условия.
Директива #else определяет начало альтернативной ветви и не является обязательной. Если условие ложно, то при ее наличии в компилируемый текст включается текст_2, при ее отсутствии весь текст от #if до #endif опускается.
Различие между директивами #if, #ifdef и #ifndef состоит в типе проверяемого условия.
Директива #if имеет формат
#if выражение
Выражение может содержать целые константы и идентификаторы. Если идентификаторы определены на препроцессорном уровне, их значение определяется макроподстановками, в противном случае они имеет нулевые значения. Проверяемое условие истинно, если константное выражение отлично от нуля.
Пример:
В результате препроцессорной обработки директив:
#if 5+4
текст_1
#endif
текст_1всегда будет включен в компилируемую программу.
Данная директива может использоваться для того, чтобы временно закомментировать фрагменты кода.
Пример:
#if 0
int i, j;
double x, y;
#endif
Директива #ifdef имеет формат
#ifdef идентификатор
Проверяемое условие истинно, если идентификатор является препроцессорным, т.е. ранее определен директивой #define.
Директива #ifndef имеет формат
#ifndef идентификатор
Проверяемое условие истинно, если идентификатор не является препроцессорным, т.е. ранее не определен директивой #defineили его определение было отменено директивой #undef.
Определение идентификатора, управляющего условной компиляцией, осуществляется с помощью третьей модификации директивы #define:
#define идентификатор
Строка замещения в данном случае отсутствует.
Директиву #ifdef удобно применять при отладке программ для включения или исключения средств вывода контрольных сообщений.
Пример:
После определения идентификатора DEBUG с помощью директивы
#define DEBUG
В программе можно использовать для вывода контрольного сообщения конструкцию
#ifdef DEBUG
printf ( “Отладочная печать”);
#endif
Оператор printf ( “Отладочная печать”); выполняется, т.к. идентификатор DEBUG ранее определен. Вывод контрольного сообщения может использоваться программе неоднократно, но убрав либо поместив в скобки комментария директиву #define DEBUG, можно отключить их все сразу.
Директива #ifndef часто применяется для того, чтобы не происходило повторного включения файлов, текст которых вставляется в программу директивой #include. Такая ситуация может иметь место, когда в одну программу подключаются несколько файлов, в каждом из которых, в свою очередь, подключается один и тот же файл. Чтобы этого не произошло, в каждый файл необходимо включить специальные средства защиты от повторного включения. Такими средствами защиты снабжены все заголовочные файлы стандартной библиотеки.
#include "filename.h" // включение текста файла filename.h
#define _FILE_NAME // определение _FILE_NAME
#endif
Здесь _FILE_NAME - зарезервированный для файла с именем filename препроцессорный идентификатор. Его нежелательно использовать в других текстах программы.
Директива #elif является составной директивой #else - #if. Она используется для организации множественных ветвлений.
Данная директива имеет формат
#elif выражение
Требования к выражению такие же, как и для директивы #if.
Формат применения данной директивы:
#if выражение_0
текст_для_if
#elif выражение_1
текст_1
#elif выражение_2
текст_2
…
#else
текст_для__еlse
#endif
Количество директив #elif является произвольным.
Препроцессор сначала проверяет выражение_0 в директиве #if. Если оно не равно 0, в компилируемый текст включается текст_для_if, если оно равно 0, вычисляется выражение_1. Если выражение_1 не равно 0 в текст включается текст_1, если оно равно 0, вычисляется выражение_2 и т.д. Если все выражения равны 0, то в компилируемый текст включается текст_для_else.
При появлении ненулевого выражения в одной из директив (#if или #elif) в компилируемый текст включается текст, расположенный после данной директивы, а все остальные директивы не рассматриваются. Таким образом, в компилируемый текст включается всегда только один из участков текста, выделенных директивами условной компиляции. Это бывает полезно при отладке или, например, при поддержке нескольких версий программы для различных платформ.
Пример:
#if VERSION == 1
#define INCFILE "versl.h"
#elif VERSION ==2
#define INCFILE "vers2.h"
#else
#define INCFILE "vers3.h"
#endif
#include INCFILE
В данном примере выполняется включения различных версий заголовочного файла.