Директивы #if, #elif, #else и #endif (C/C++)
Директива #if вместе с директивами #elif, #else и #endif управляет компиляцией частей исходного файла. Если указанное выражение (после #if) имеет ненулевое значение, в записи преобразования сохраняется группа строк, следующая сразу за директивой #if.
Грамматика
условные:
if-часть elif-частинеоб else-частьнеоб endif-строкаif-часть :
текст строки-ifif-строка :
#if константное-выражение#ifdef идентификатор
#ifndef идентификатор
elif-части :
elif-текст-строкиelif-части elif-текст-строки
elif-строка :
#elif константное-выражениеelse-часть :
текст строки-elseelse-строка :
#elseendif-строка :
#endif
У каждой директивы #if в исходном файле должна быть соответствующая закрывающая директива #endif. Между директивами #if и #endif может располагаться любое количество директив #elif, однако допускается не более одной директивы #else. Директива #else, если присутствует, должна быть последней перед директивой #endif.
Директивы #if, #elif, #else и #endif могут быть вложены в другие текстовые части директив #if. Каждая вложенная директива #else, #elif или #endif относится к ближайшей предшествующей директиве #if.
У всех директив условной компиляции, таких как #if и #ifdef, до конца файла должны быть соответствующие закрывающие директивы #endif; в противном случае появляется сообщение об ошибке. Если директивы условной компиляции содержатся во включаемых файлах, они должны удовлетворять одинаковым условиям: в конце включаемого файла не должно оставаться непарных директив условной компиляции.
Внутри той части командной строки, которая следует за командой #elif, выполняется подстановка макросов, поэтому вызовы макросов можно использовать в выражении константное-выражение.
Препроцессор выбирает одно из заданных вхождений параметра текст для дальнейшей обработки. Блок, указанный в параметре текст, может представлять собой любую последовательность текста. Он может занимать несколько строк. Обычно текст — это текст программы, понятный для компилятора или препроцессора.
Препроцессор обрабатывает выделенный блок текст и передают его компилятору. Если блок текст содержит директивы препроцессора, препроцессор выполняет эти директивы. Компилируются только текстовые блоки, выбранные препроцессором.
Препроцессор выбирает один элемент текст, оценивая константные выражения, следующие за каждой директивой #if или #elif, до тех пор, пока не будет найдено выражение со значением true (отличное от нуля). Выделяется весь текст (включая другие директивы препроцессора, начинающиеся с символа #) до соответствующей директивы #elif, #else или #endif.
Если все вхождения константного-выражения имеют значение false или нет ни одной директивы #elif, препроцессор выбирает блок текста после предложения #else. Если предложение #else опущено и все экземпляры константного-выражения в блоке #if имеют значение false, ни один текстовый блок не выбирается.
Константное-выражение — это целочисленное константное выражение со следующими дополнительными ограничениями:
Выражения должны иметь целочисленный тип и могут содержать только целочисленные константы, символьные константы и оператор defined.
В выражении не допускается использование оператора sizeof или оператора приведения типа.
Целевая среда может быть не в состоянии представлять все диапазоны целых чисел.
Преобразование представляет тип int, совпадающий с типом long, и тип unsigned int, совпадающий с типом unsigned long.
Транслятор может преобразовывать символьные константы в набор кодовых значений, отличающийся от набора для целевой среды. Для определения свойств целевой среды проверьте значения макросов из файла LIMITS.H в приложении, собранном для целевой среды.
Выражение не должно выполнять никаких запросов среды и не должно зависеть от конкретной реализации на целевом компьютере.
Оператор препроцессора defined можно использовать в специальных константных выражениях, как показано в следующем синтаксисе:
defined( identifier )
defined identifier
Это константное выражение считается равным true (не равным нулю), если в данный момент идентификатор определен; в противном случае условие равно false (0). Идентификатор, определенный как пустой текст, считается определенным. Директиву defined можно использовать только в директивах #if и #elif.
В следующем примере директивы #if и #endif управляют компиляцией вызова одной из 3 функций:
#if defined(CREDIT)
credit();
#elif defined(DEBIT)
debit();
#else
printerror();
#endif
Вызов функции credit компилируется, если определен идентификатор CREDIT. Если определен идентификатор DEBIT, компилируется вызов функции debit. Если ни один из этих идентификаторов не определен, компилируется вызов функции printerror. Обратите внимание, что в C и C++ идентификаторы CREDIT и credit — это разные идентификаторы из-за различного регистра символов.
В следующем примере в операторах условной компиляции используется ранее определенная символьная константа с именем DLEVEL.
#if DLEVEL > 5
#define SIGNAL 1
#if STACKUSE == 1
#define STACK 200
#else
#define STACK 100
#endif
#else
#define SIGNAL 0
#if STACKUSE == 1
#define STACK 100
#else
#define STACK 50
#endif
#endif
#if DLEVEL == 0
#define STACK 0
#elif DLEVEL == 1
#define STACK 100
#elif DLEVEL > 5
display( debugptr );
#else
#define STACK 200
#endif
Первый блок #if содержит 2 набора вложенных директив #if, #else и #endif. Первый набор директив обрабатывается только в том случае, если выполняется условие DLEVEL > 5. В противном случае обрабатываются операторы, расположенные после директивы #else.
Директивы #elif и #else во втором примере используются для выбора одного из четырех вариантов в зависимости от значения константы DLEVEL. Константе STACK присваивается значение 0, 100 или 200 в зависимости от определения константы DLEVEL. Если DLEVEL больше 5, то компилируется оператор
#elif DLEVEL > 5
display(debugptr);
и константа STACK остается неопределенной.
Условная компиляция обычно используется для предотвращения нескольких включений одного и того же файла заголовка. В языке C++, в котором классы часто определяются в файлах заголовков, конструкции, подобные приведенным ниже, можно использовать для исключения многократных определений.
/* EXAMPLE.H - Example header file */
#if !defined( EXAMPLE_H )
#define EXAMPLE_H
class Example
{
...
};
#endif // !defined( EXAMPLE_H )
Предыдущий код проверяет, определена ли символьная константа EXAMPLE_H. Если определена, файл уже включен и его повторная обработка не требуется. Если нет, константа EXAMPLE_H определяется, чтобы пометить файл EXAMPLE.H как уже обработанный.