C/C++ Директивы препроцессора
Препроцессор — это специальная программа, являющаяся частью компилятора языка Си. Она предназначена для предварительной обработки текста программы. Препроцессор позволяет включать в текст программы файлы и вводить макроопределения.
Работа препроцессора осуществляется с помощью специальных директив (указаний). Они отмечаются знаком решетка #. По окончании строк, обозначающих директивы в языке Си, точку с запятой можно не ставить.
Основные директивы препроцессора
#include — вставляет текст из указанного файла
#define — задаёт макроопределение (макрос) или символическую константу
#undef — отменяет предыдущее определение
Директива #include позволяет включать в текст программы указанный файл. Если заголовочный файл содержит описание библиотечных функций и находится в папке компилятора, он заключается в угловые скобки <>.
Если файл находится в текущем каталоге проекта (или путь прописан в IDE), он указывается в кавычках “”. Для файла, находящегося в другом каталоге необходимо в кавычках указать полный путь.
Директива #define позволяет вводить в текст программы константы и макроопределения.
Общая форма записи: #define Идентификатор Замена
Благодаря директиве #define компилятор,вместо каждого аргумента Идентификатор в исходном файле подставляет выражение, скрытое под именем “замена”. Идентификатор не заменяется, если он находится в комментарии, в строке или как часть более длинного идентификатора.
#define PI 3.14
В зависимости от значения константы компилятор присваивает ей тот или иной тип. С помощью суффиксов можно переопределить тип константы:
U или u представляет целую константу в беззнаковой форме (unsigned);
F (или f) позволяет описать вещественную константу типа float;
L (или l) позволяет выделить целой константе 8 байт (long int);
L (или l) позволяет описать вещественную константу типа long double
#define A 280U // unsigned int
Создание функций с помощью defines
С помощью дефайнов можно создавать простые функции (зачастую “магические/калибровочные”), синтаксис в общем виде выглядит так:
#define название(аргумент_1, …, агрумент_n) (реализация)
Важно – каждый операнд указывать в скобках, иначе при вычислении
#define Dev_p10(a) ((a)%10)
Dev_p10(19+10) получим результат 19 т.к. 19+10%10=19+0=19
Условная компиляция
#if — осуществляет условную компиляцию при истинности константного выражения
#ifdef — осуществляет условную компиляцию при определённости символической константы
#ifndef — осуществляет условную компиляцию при неопределённости символической константы
#else — ветка условной компиляции при ложности выражения
#elif — ветка условной компиляции, образуемая слиянием else и if
#endif — конец ветки условной компиляции
#line — препроцессор изменяет номер текущей строки и имя компилируемого файла
#error — выдача диагностического сообщения
#pragma — действие, зависящее от конкретной реализации компилятора.
Директивы #if или #ifdef/#ifndef вместе с директивами #elif, #else и #endif управляют компиляцией частей исходного файла.
Если указанное выражение после #if имеет ненулевое значение, в записи преобразования сохраняется группа строк, следующая сразу за директивой #if. Синтаксис условной директивы следующий:
#if/ifdef/ifndef константное выражение
группа операций
#elif константное выражение
группа операций
#else
группа операций
#endif
У каждой директивы #if… в исходном файле должна быть соответствующая закрывающая директива #endif. Между директивами #if и #endif может располагаться любое количество директив #elif, однако допускается не более одной директивы #else. Директива #else, если присутствует, должна быть последней перед директивой #endif.
Условную компиляцию удобно применять в отладочных целях – если задать #define Debug
#define Debug
// то когда будет код
#ifdef Debug
//code
#endif
//Аналогичное с #if
#if Debug < 4
//code
#endif
Отменить макроопределение можно с помощью директивы #undef.
