Оператор defined
При условной обработке текста для упрощения записи сложного условия выбора можно использовать унарный препроцессорный оператор
defined операнд
Где операнд - либо идентификатор, либо заключенный в скобки идентификатор, либо обращение к макросу. Если идентификатор операнда до этого определен с помощью команды #define как препроцессорный, то выражение defined операнд считается истинным. В противном случае – ложным. Поясним с помощью примера полезные возможности операции defined. Предположим, что некоторый _текст должен быть передан компилятору только в том случае, если идентификатор Y определен как препроцессорный, а идентификатор N не определен. Не используя операцию defined, это условие можно записать так:
#ifdef Y
#ifndef N
_текст
#endif
#endif
Используя defined получим
#if defined Y &&!defined N
_текст
#endif
Таким образом, из примера видно, что:
#if defined эквивалентно #ifdef
#if!defined эквивалентно #ifndef
Стандарт языка Си не определил defined в качестве ключевого слова. В тексте программы его можно использовать в качестве идентификатора, свободно применяемого программистом для обозначения объектов. defined имеет специфическое значение только при формировании выражений-условий, проверяемых в директивах #if и #elif В то же время идентификатор defined запрещено использовать в директивах #define и #undef.
Макрос, по определению, есть средство замены одной последовательности символов на другую. Для выполнения замен должны быть заданы соответствующие макроопределения. Простейшее макроопределение мы уже ввели, рассматривая замены в тексте с помощью директивы
#define идентификатор строка_замещения
С помощью директивы #define программист может вводить собственные обозначения базовых или производных типов. Например, директива
# define REAL long double
вводит название (имя) REAL. Далее в тексте программы можно определять конкретные объекты, используя REAL в качестве обозначения их типа long double.
Идентификатор в команде #define может определять имя константы, если строка_замещения задает значение константы. В общем случае идентификатор служит обозначением некоторого выражения, например:
##define RANGE ((INT_MAX)-(INT_MIN1) +1)
Идентификаторы, входящие в строку замещения, в свою очередь, могут быть определены как препроцессорные. Однако большие возможности предоставляет макроопределение с параметрами:
#define имя(список_параметров) строка_замещения
Здесь имя - имя макроса (идентификатор),
список_параметров - список разделенных запятыми идентификаторов. Между именем макроса и скобкой, открывающей список параметров, не должно быть пробелов.
Для обращения к макросу ("для вызова макроса") используется конструкция ("макровызов") вида:
имя_макроса(список_аргументов)
В списке аргументы разделены запятыми. Каждый аргумент препро-цессорная лексема. Классический пример макроопределения:
#define max(x,y) (x<y?y:x)
позволяет формировать в программе выражение, определяющее максимальное из двух значений аргументов. При таком определении вхождение в программу макровызова
max(a,b) заменяется выражением:(a<b?b:a).