Имеется несколько директив, которые дают возможность выборочно компилировать части исходного кода вашей программы. Этот процесс называется условной компиляцией и широко используется фирмами, живущими за счет коммерческого программного обеспечения — теми, которые поставляют и поддерживают многие специальные версии одной программы.
Возможно, самыми распространенными директивами условной компиляции являются #if, #else, #elif и #endif. Они дают возможность в зависимости от значения константного выражения включать или исключать те или иные части кода.
В общем виде директива #if выглядит таким образом:
#if константное выражение последовательность операторов #endif
Если находящееся за #if константное выражение истинно, то компилируется код, который находится между этим выражением и #endif. В противном случае этот промежуточный код пропускается. Директива #endif обозначает конец блока #if. Например,
/* Простой пример #if. */ #include <stdio.h> #define MAX 100 int main(void) { #if MAX>99 printf("Компилирует для массива, размер которого больше 99.\n"); #endif return 0; }
Это программа выводит сообщение на экран, потому что МАХ больше 99. В этом примере показано нечто очень важное. Значение выражения, находящегося за директивой #if, должно быть вычислено во время компиляции. Поэтому в этом выражении могут находиться только ранее определенные идентификаторы и константы, — но не переменные.
Директива #else работает в основном так, как else — ключевое слово языка С: задает альтернативу на тот случай, если не выполнено условие #if. Предыдущий пример можно дополнить следующим образом:
/* Простой пример #if/#else. */ #include <stdio.h> #define MAX 10 int main(void) { #if MAX>99 printf("Компилирует для массива, размер которого больше 99.\n"); #else printf("Компилирует для небольшого массива.\n"); #endif return 0; }
В этом случае выясняется, что МАХ меньше 99, поэтому часть кода, относящаяся к #if, не компилируется. Однако компилируется альтернативный код, относящийся к #else, и откомпилированная программа будет отображать сообщение Компилируется для небольшого массива.
Обратите внимание, что директива #else используется для того, чтобы обозначить и конец блока #if, и начало блока #else. Это естественно, поскольку любой директиве #if может соответствовать только одна директива #endif.
Директива #elif означает "else if" и устанавливает для множества вариантов компиляции цепочку if-else-if. После #elif находится константное выражение. Если это выражение истинно, то компилируется находящийся за ним блок кода, и больше не проверяются никакие другие выражения #elif. В противном же случае проверяется следующий блок этой последовательности. В общем виде #elif выглядит таким образом:
#if выражение последовательность операторов #elif выражение 1 последовательность операторов #elif выражение 2 последовательность операторов #elif выражение 3 последовательность операторов #elif выражение 4 . . . #elif выражение N последовательность операторов #endif
Например, в следующем фрагменте для определения знака денежной единицы используется значение ACTIVE_COUNTRY (для какой страны):
#define US 0 #define ENGLAND 1 #define FRANCE 2 #define ACTIVE_COUNTRY US #if ACTIVE_COUNTRY == US char currency[] = "dollar"; #elif ACTIVE_COUNTRY == ENGLAND char currency[] = "pound"; #else char currency[] = "franc"; #endif
В соответствии со стандартом С89 у директив #if и #elif может быть не менее 8 уровней вложенности. А в соответствии со стандартом С99 программистам разрешается использовать не менее 63 уровней вложенности. При вложенности каждая директива #endif, #else или #elif относится к ближайшей директиве #if или #elif. Например, совершенно правильным является следующий фрагмент кода:
#if MAX>100 #if SERIAL_VERSION int port=198; #elif int port=200; #endif #else char out_buffer[100]; #endif
Другой способ условной компиляции — это использование директив #ifdef и #ifndef, которые соответственно означают "if defined" (если определено) и "if not defined" (если не определено). В общем виде #ifdef выглядит таким образом:
#ifdef имя_макроса последовательность операторов #endif
Блок кода будет компилироваться, если имя макроса было определено ранее в операторе #define.
В общем виде оператор #ifndef выглядит таким образом:
#ifndef имя_макроса последовательность операторов #endif
Блок кода будет компилироваться, если имя макроса еще не определено в операторе #define.
И в #ifdef, и в #ifndef можно использовать оператор #else или #elif. Например,
#include <stdio.h> #define TED 10 int main(void) { #ifdef TED printf("Привет, Тед\n"); #else printf("Привет, кто-нибудь\n"); #endif #ifndef RALPH printf("А RALPH не определен, т.ч. Ральфу не повезло.\n"); #endif return 0; }
выведет Привет, Тед, а также A RALPH не определен, т.ч. Ральфу не повезло.
В соответствии со стандартом С89 допускается не менее 8 уровней #ifdef и #ifndef. А стандарт С99 устанавливает, что должно поддерживаться не менее 63 уровней вложенности.