Препроцессор – это процессор, манипулирующий исходным текстом Си программы на первой стадии ее компиляции.
Управление работой препроцессора производится посредством директив препроцессора. Обработанный препроцессором исходный текст поступает компилятору и он уже не содержит директив препроцессора. Директивы препроцессора отмечаются специальным маркером – знаком номера (#). Между знаком номера и первой буквой директивы могут находиться пробелы.
Директивы препроцессора могут появиться в любом месте исходного файла, но они применимы только к остатку исходного файла. Директивы дают команду препроцессору заменить тот или иной идентификатор некоторым значением, выполнить операцию макроопределения, включить текст некоторого файла в данный файл, “подавить” компиляцию части программы посредством условной компиляции.
Директива # define
Эта директива имеет два формата:
- #define идентификатор текст_подстановки
- #define идентификатор(список параметров) текст_подстановки
Первый формат определяет простую подстановку. То есть в тексте исходного файла, следующем за директивой #define, все вхождения идентификатора заменяются на текст подстановки, определенный в директиве справа от идентификатора.
|
|
Текст подстановки может быть опущен. В этом случае удаляются все вхождения идентификатора из текста исходной программы.
Пример:
#define PI 3.1415926
Второй формат позволяет определить макрокоманды с аргументами. Если после идентификатора следует список параметров, то в исходном тексте, следующем за директивой #define, каждое вхождение выражения идентификатор(список параметров) заменяется на текст подстановки с заменой формальных параметров фактическими.
Пример:
#define MIN(x,y) ((x)<y?(x):(y)) /* минимум из x и y */
Замечание:
· параметры макроопределения заключают в круглые скобки;
· макроопределение не заканчивается точкой с запятой.
Пример:
#define КУБ(x) (x*x*x)
КУБ(a+3) /* (a+3*a+3*a+3), а должно быть (a+3)*(a+3)*(a+3) */
Директива # include
Эта директива имеет формат:
- #include<спецификатор маршрута>
- #include “спецификатор маршрута”
Спецификатор маршрута – это имя файла с предшествующей спецификацией каталога.
Директива #include добавляет содержимое заданного файла включения к другому файлу. Включаемые файлы также могут содержать директивы препроцессора. Препроцессор выполняет директивы из нового файла, а затем продолжает обработку текста исходного файла.
Если имя файла заключено в скобки, то файл берется из некоторого стандартного каталога, а текущий каталог не просматривается. Если имя файла дано в кавычках, то препроцессор ищет файл в текущем каталоге. Если его там нет, то ищется в стандартном каталоге.
|
|
Директивы условной компиляции
Это директивы #if, #elif, #else, #endif
Эти директивы позволяют отменить компиляцию отдельных частей исходного файла посредством проверки константных выражений или идентификаторов, и имеют следующий формат:
#if константное выражение_1
[текст]
[#elif константное выражение_2
текст]
[#elif константное выражение_3
текст]
…
[#else
текст]
#endif
Каждой директиве #if в исходном файле должна соответствовать закрывающая директива #endif. Между ними может быть несколько директив #elif и не более одной #else.
Директива #else, если она есть, должна быть последней директивой перед директивой #endif.
Препроцессор выбирает одно из вхождений текста, на основе вычисления константного выражения. Выбирается то, где будет найдено выражение со значением истина (не ноль). Если все выражения ложны или отсутствует директива #elif, то текст берется после директивы #else. Если эта директива отсутствует, то никакой текст не выбирается.
Константное выражение – это выражение из различных констант, исключая константы типа enum (перечисление).