Директивы условной компиляции

Содержание

Имеется несколько директив, которые дают возможность выборочно компилировать части исходного кода вашей программы. Этот процесс называется условной компиляцией и широко используется фирмами, живущими за счет коммерческого программного обеспечения — теми, которые поставляют и поддерживают многие специальные версии одной программы.

Директивы #if, #else, #elif и #endif


Возможно, самыми распространенными директивами условной компиляции являются #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


Другой способ условной компиляции — это использование директив #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 уровней вложенности.