- •Стадии препроцессорной обработки
- •Макроопределение без параметров
- •Пример:
- •Пример:
- •Пример:
- •Цепочка подстановок
- •Сравнение макросов и функций
- •Пример:
- •Пример:
- •Пример:
- •Int II, jj, ll; // целые внешние переменные
- •Условная компиляция
- •Пример:
- •Пример:
- •Пример:
- •Вспомогательные директивы
- •Пример:
- •Void main ( ) // строка 2
- •Пример:
Пример:
#if defined Y && !defined N
текст
#endif
Текст включается в компилируемый текст только в том случае, если идентификатор Y определен как препроцессорный, а идентификатор N не определен.
Обработку препроцессор ведет следующим образом. Сначала, определяется истинность выражений defined Y и !defined N. К результатам применяется операция конъюнкции &&, и при истинности ее результата текст передается компилятору.
Не используя операцию defined, то же самое условие можно записать таким способом:
#ifdef Y
#ifndef N
текст
#endif
#endif
Таким образом, из примера видно, что
#if defined эквивалентно #ifdef
#if !defined эквивалентно #ifndef
Стандарт языка С++ не определил defined в качестве ключевого слова. В тексте программы его можно использовать в качестве идентификатора. Специфическое значение имеет defined только при формировании условий, проверяемых в директивах #if и #elif. Запрещено использовать defined в директивах #define и #undef.
Вспомогательные директивы
Кроме рассмотренных ранее директив #include, #define и директив команд условной компиляции существует еще несколько вспомогательных директив, которые не так часто используются в практике программирования.
Директива #line позволяет управлять нумерацией строк в файле с программой, а также изменять имя файла.
После препроцессорной обработки каждая строка текста передаваемого на компиляцию имеет следующий вид:
имя_файла номер_строки: текст_на_языке_С++
Директива #line имеет следующий формат:
Для нумерации строк можно использовать директиву
#line номер_строки [“имя_файла”]
Данная директива позволяет изменять номер и имя файла следующей за ней строки на указанные значения.
Пример:
Препроцессор получает для обработки файл "www.c" с текстом:
#define N 3 // строка 1
Void main ( ) // строка 2
{ // строка 3
#line 23 "file.с" // строка 4
double z[3*N]; // строка 5
} // строка 6
После препроцессорной обработки в файле с именем "www.i" будет получен следующий набор строк:
www.c 1:
www.c 2: void main ( )
www.c 3: {
www.c 4:
file.c 23: double z[3*3]
file.c 24: }
Из текста исключены препроцессорные директивы и комментарии. При этом строки, где размещались директивы препроцессора (1 и 4), вошли в компилируемый текст, как пустые строки. Следующей за директивой #line строке присвоен номер 23 и имя файла "file.c" в соответствие с указанными значениями. Следующая строка имеет такое же имя файла и номер строки на единицу больше.
Директива #line может использоваться в случае, когда текст программы на языке С++ генерирует какой-то другой препроцессор.
Директива #error задает текст сообщения, которое выводится при возникновении ошибок компиляции.
Она имеет следующий формат:
#error текст_сообщения
Выполнение данной директивы приводит к выдаче диагностического сообщения, содержащего указанный текст. Текст может содержать препроцессорные идентификаторы. Директива #error может применяться совместно с директивами условной компиляции.
Пример:
Определив некоторую препроцессорную переменную NAME
#define NAME 5
можно проверять, не изменилось ли ее значение, и выдавать в этом случае сообщение:
#if (NAME != 5)
#error NAME должно быть равно 5
В интегрированной среде (например, Turbo С) сообщение будет выдано на этапе компиляции в виде:
Fatal <имя_файла> <номер_строки>:
Error directive: NAME должно быть равно 5
В случае выявления такой аварийной ситуации дальнейшая препроцессорная обработка исходного текста прекратиться, и в компилируемый текст попадет только та часть текста, которая предшествует директиве #if.
Директива #pragma вызывает действия, зависящие от конкретной реализации компилятора.
Она имеет следующий формат
#pragma последовательность _лексем
Данная конструкция называется прагмой. Стандарта для прагм не существует. Если конкретный препроцессор встречает прагму, которая ему неизвестна, он ее игнорирует.
В некоторых реализациях включена директива
#pragma pack(n)
n может быть равно 1, 2 или 4.
Данная прагма позволяет влиять на упаковку смежных элементов в структурах и объединениях. Соглашение может быть таким:
pack(l) - выравнивание элементов по границам байтов;
раск(2) - выравнивание элементов по границам слов;
раск(4) - выравнивание элементов по границам двойных слов.
В некоторые компиляторы включены прагмы, позволяющие изменять способ передачи параметров функциям, порядок помещения параметров в стек, сообщать компилятору о наличии в тексте программы команд на языке ассемблера и т.д.
Существует также пустая директива, использование которой не вызывает никаких действий. Она имеет вид:
#