Препроцессор и библиотека С 679
посредством #undef, то идентификатор определен. Если идентификатор — не макрос, а, скажем, переменная с областью действия на уровне файла, то с точки зрения препроцессора он не определен.
Определенным может быть объектный макрос, включая пустой макрос, или функциональный макрос:
#define LIMIT 1000 // идентификатор LIMIT определен
#define GOOD // идентификатор GOOD определен
#define А(X) ((-(X))*(X)) // идентификатор А определен
int q; // идентификатор q - не макрос, поэтому не определен
#undef GOOD // идентификатор GOOD не определен
Обратите внимание, что область действия макроса #def ine начинается с места его объявления в файле и продолжается вплоть до соответствующей директивы #undef либо до конца файл в зависимости от того, что случится первым. Кроме того, имейте в виду, что позиция директивы #define в файле будет зависеть от местоположения директивы #include, если макрос поступает из заголовочного файла.
Несколько предопределенных макросов, таких как____ DATE_ и___ FILE__ (обсуж
даются позже в главе), всегда считаются определенными, причем их определение не может быть отменено.
Условная компиляция
Остальные из упомянутых директив можно применять для настройки условной компиляции. Это значит, что их можно использовать для сообщения компилятору о том, принимать либо игнорировать блоки информации или кода согласно условиям на этапе компиляции.
Директивы #ifdef, #else И #endif
Следующий краткий пример прояснит, что делает условная компиляция. Взгляните на следующий код:
#ifdef MAVIS
#include "horse.h" // выполняется, если идентификатор MAVIS определен #define STABLES 5 #else
#include "cow.h" // выполняется, если идентификатор MAVIS не определен #define STABLES 15 #endif
Здесь мы применили отступы, разрешаемые новыми реализациями языка и стандартом ANSI. В случае более старых реализаций может потребоваться выровнять влево все директивы или хотя бы символы #:
#ifdef MAVIS
# include "horse.h" /* выполняется, если идентификатор MAVIS определен */
# define STABLES 5
#else
# include "cow.h" /* выполняется, если идентификатор MAVIS не определен */
# define STABLES 15 #endif
Директива #ifdef говорит о том, что если следующий за ней идентификатор (MAVIS) был определен препроцессором, необходимо обработать все директивы и
680 Глава 16 скомпилировать весь код С до следующей директивы #else или #endif в зависимости от того, что встретится раньше. Если предусмотрена директива #else, то должен быть обработан весь код между #else и #endif, когда идентификатор не определен.
Форма #ifdef #else во многом подобна оператору if else языка С. Основное отличие в том, что препроцессор не распознает фигурные скобки (I]) как метод обозначения блока, поэтому для пометки блоков директив используются директивы #else (если есть) и #endif (должна присутствовать). Такие условные структуры могут быть вложенными. Как иллюстрируется в листинге 16.9, эти директивы можно применять также для пометки блоков операторов С.
Листинг 16.9. Программа ifdef .о

В результате компиляции и выполнения программы будет получен следующий вывод:
i = 1, промежуточная сумма = 3 i=2, промежуточная сумма = 12 1=3, промежуточная сумма = 31 1=4, промежуточная сумма = 64 Итоговая сумма = 64
Если опустить определение JUST_CHECKING (или поместить его в комментарий либо отменить определение с помощью директивы #undef) и повторно скомпилировать программу, отобразится только последняя строка. Таким приемом можно пользоваться, например, при отладке программы.
Определите идентификатор JUST_CHECKING и задействуйте его в условных выборах с помощью #ifdef; компилятор будет включать программный код для вывода промежуточных значений в целях отладки. После отладки определение можно удалить и повторно скомпилировать программу. Если впоследствии снова потребуется вывод промежуточных значений, можно опять вставить определение и избавить себя от необходимости повторно набирать все дополнительные операторы вывода.
Еще одной возможностью является применение #ifdef для выбора альтернативных блоков кода, приспособленных к разным реализациям С.
Препроцессор и библиотека С 681
Директива #ifndef
Директива #ifndef может использоваться совместно с директивами #else и #endif тем же самым способом, что и #ifdef. Директива #ifndef выясняет, не определен ли следующий за ней идентификатор; она представляет собой инверсию директивы #ifdef. Эта директива часто применяется для определения константы, если она еще не была определена. Ниже приведен пример.
Читать дальше