- Включение исходных файлов (#include)
- Обзор директив макроподстановки
- Простая форма #define
- Форма #define в виде псевдо-функции
- Специальные операторы '#' и '##' внутри определений #define
- Отмена макроподстановки (#undef)
- Предопределенные константы препроцессора
- Условная компиляция (#ifdef/#ifndef/#else/#endif)
- Общие свойства программ (#property)
Специальные операторы '#' и '##' внутри определений #define
Внутри определений макросов можно использовать два специальных оператора:
- Одиночный символ решетки '#', стоящий перед именем параметра макроса, превращает содержимое этого параметра в строку. Разрешен только в макросах-функциях.
- Сдвоенный символ решетки '##', стоящий между двумя словами (токенами) объединяет их. Причем если токен является параметром макроса, то подставляется его значение, а если токен — имя макроса, оно подставляется как есть, без раскрытия макроса. Если в результате "склейки" получается другое имя макроса, он раскрывается.
В примерах данной книги мы часто использовали следующий макрос:
#define PRT(A) Print(#A, "=", (A)) |
Он вызывает функцию Print, в которой переданное выражение отображается в виде строки благодаря #A, а после знака равно выводится актуальное значение A.
Для демонстрации '##' рассмотрим другой макрос:
#define COMBINE(A,B,X) A##B(X) |
С помощью него мы можем фактически сгенерировать вызов определенного выше макроса SQN:
Print(COMBINE(SQ,N,2)); // 4 |
Литералы SQ и N объединяются, после чего макрос SQN раскрывается в ((2)*(2)) и дает результат 4.
Следующий макрос позволяет создать определение переменной в коде, сгенерировав её имя с учетом параметров макроса:
#define VAR(TYPE,N) TYPE var##N = N |
Тогда строка кода:
VAR(int, 3); |
эквивалентна записи:
int var3 = 3; |
Сцепка токенов позволяет реализовать с помощью макроса краткую форму записи цикла по элементам массива.
#define for_each(I, A) for(int I = 0, max_##I = ArraySize(A); I < max_##I; ++I)
|