C++ Программирование в среде С++ Builder 5

         

Макроопределения


Макроопределения, называемые в просторечии макросами, определяются директивой препроцессора #define. Можно выделить три формы макросов #define: простое определение символа, определение символической константы и определение макроса с параметрами.

Простое определение выглядит так:

#define NDEBUG

После такой директивы символ NDEBUG считается определенным. Не предполагается, что он что-то означает; он просто — определен (как пустой). Можно было бы написать:

#define NDEBUG 1

Тогда NDEBUG можно было бы использовать и в качестве символической константы, о которых говорилось в предыдущей главе. Всякое вхождение в текст лексемы NDEBUG препроцессор заменил бы на “I”. Зачем нужны макроопределения, которые ничего не определяют, выяснится при обсуждении условных конструкций препроцессора.

Как вы могли бы догадаться, #define может определять не только константы. Поскольку препроцессор выполняет просто текстовую подстановку, можно сопоставить символу и любую последовательность операторов, как показано ниже:

#define SHUTDOWN \

printf("Error!"); \ return -1

if (ErrorCondition()) SHUTDOWN; // "Вызов" макроса.

Обратная дробная черта (\) означает, что макрос продолжается на следующей строчке. В отличие от операторов С директивы препроцессора должны располагаться в одной строке, и поскольку это технически не всегда возможно, приходится явно вводить некоторый признак продолжения.

Определенный ранее макрос можно аннулировать директивой #undef:

#undef NDEBUG

После этого макрос становится неопределенным, и последующие ссылки на него будут приводить к ошибке при компиляции.



Предопределенные макросы

Компилятор C++Builder автоматически определяет некоторые макросы. Их можно разбить на две категории: макросы ANSI и макросы, специфические для C++Builder. Сводки предопределенных макросов даны соответственно в таблицах 4.1 и 4.2.

Таблица 4.1. Предопределенные макросы ANSI

Макрос

Описание

DATE Литеральная строка в формате “mmm dd yyyy”, представляющая дату обработки данного файла препроцессором.
FILE Строка имени текущего файла (в кавычках).
LIME Целое, представляющее номер строки текущего файла.
STDC Равно 1, если установлена совместимость компилятора со стандартом ANSI (ключ -А командной строки). В противном случае макрос не определен.
TIME Строка в формате “hh:mm:ss”, представляющее время препроцессорной обработки файла.
<


Значения макросов _file_ и _line_ могут быть изменены директивой #line (см. далее).



Таблица 4.2. Предопределенные макросы C++Builder

Макрос



Значение



Описание

ВСОРТ 1 Определен в любом оптимизирующем компиляторе.
BCPLUSPLUS 0х0540 Определен, если компиляция производится в режиме C++. В последующих версиях будет увеличиваться.
BORLANDC 0х0540 Номер версии.
CDECL 1 Определен, если установлено соглашение о вызове cdecl; в противном случае не определен.
CHARUNSIGNED 1 Определен по умолчанию (показывает, что char по умолчанию есть unsigned char). Можно аннулировать ключом -К.
CONSOLE Определен при компиляции консольных приложений.
CPPUNWIND 1 Разрешение разматывания стека; определен по умолчанию. Для аннулирования можно применить ключ -xd-.
cplusplus 1 Определен при компиляции в режиме C++.
DLL 1 Определен, если компилируется динамическая библиотека.
FLAT 1 Определен при компиляции в 32-битной модели памяти.
MIХ86 Определен всегда. Значение по умолчанию — 300. (Можно изменить значение на 400 или 500, применив соответственно ключи /4 или /5 в командной строке.)
MSDOS 1 Целая константа.
MT 1 Определен, если установлена опция -WM. Она означает, что будет присоединяться мультили-нейная (multithread) библиотека.
PASCAL 1 Определен, если установлено соглашение о вызове Pascal.
TCPLUSPLUS 0х0540 Определен, если компиляция производится в режиме C++ (аналогично bcplusplus ).
TEMPLATES 1 Определен для файлов C++ (показывает, что поддерживаются шаблоны).
TLS 1 Thread Local Storage. В C++Builder определен всегда.
TURBOC 0х0540 Номер версии (аналогичен BORLANDC ).
WCHAR T 1 Определен только в программах C++ (показывает, что wear t — внутренне определенный тип.
WCAR T DEFINED 1 То же, что и WCHAR Т.
Windows Определен для кода, используемого только в Windows.
WIN32 1 Определен для консольных и GUI-приложений.
<


Как видите, многие предопределенные макросы C++Builder отражают те или иные установки параметров компиляции, задаваемые в командной строке (при ручном запуске компилятора Ьсс32.ехе). Те же самые установки могут быть выполнены и в интегрированной среде через диалог Project Options, который мы еще будем рассматривать в этой главе.



Макросы с параметрами



Макросы могут выполнять не только простую текстовую подстановку. Возможно определение макросов с параметрами, напоминающих функции языка С, например:

#define PI 3.14159265

#define SQR(x) ( (x) * (x) )

#define AREA(x) (PI * SQR(x))

#define MAX(a, b) (<a)>(b) ? (a): (b))



circleArea = AREAfrl + r2);

cMax = MAX(i++, j++);

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



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



#define SQR(x) х*х binom = -SQR(a + b) ;

При расширении макроса получится:

binom = -a + b*a + b;

Порядок оценки выражения окажется совсем не тем, что подразумевался.



Преобразование в строку



В макросах может применяться специальная операция преобразования в строку (#). Если в расширении макроса параметру предшествует эта опе-

рация, то выражение-аргумент будет преобразовано в литеральную строку, заключенную в двойные кавычки. Вот один пример:

#define SHOWINT(var)

printf(#var " = %d\n", (int)(var))

int iVariable = 100;

SHOWINT(iVariable) ;

Последняя строчка расширяется в

printf("iVariable"" = %d\n", (int)(iVariable));

и печатает

iVariable = 100



В С примыкающие друг к другу литеральные строки при компиляции соединяются в одну строку.



Конкатенация



Операция конкатенации (##) позволяет составить из нескольких лексем единое слово. Получившийся элемент повторно сканируется для обнаружения возможного идентификатора макроса. Рассмотрите такой код:

#define DEF_INT(n) int iVar ## n



DEF_INT(One); // Расширяется в int iVarOne;

DEF_INT(Two); // Расширяется в int iVarTwo; и т.д.


Содержание раздела