Директивы препроцессора.

Стадии и команды препроцессорной обработки

Препроцесссор С. Условная компиляция и замены текста в программе С

 

Прежде всего отметим, что препроцессор обрабатывает почти любые тексты, а не только тексты на языке С!!!, хосновное отя назначение препроцессора – обработка исходного текста программы до ее компиляции.

Стадии препроцессорной обработки. Препроцессорная обработка включает несколько стадий, выполняемых последовательно. Конкретная реализация может объединять несколько стадий, но результат должен быть таким, как если бы они выполнялись в следующем порядке:

• все системно-зависимые обозначения (например, системно-зависимые индикатор конца строки) перекодируются в стандартные коды;

• каждая пара из символов '\' и "конец строки" вместе с пробелами между ними убираются, и тем самым следующая строка исходного текста присоединяется к строке, в которой находилась эта пара символов;

• в тексте (точнее, в тексте каждой отдельной строки) распознаются директивы и лексемы препроцессора, а каждый комментарии заменяется одним символом пустого промежутка;

• выполняются директивы препроцессора и производятся макроподстановки;

• эскейп-последовательности в символьных константах и символьных строках, например '\n' или '\xF2', заменяются на их эквиваленты (на соответствующие числовые коды);

• смежные символьные строки (строковые константы) конкатенируются, т.е. соединяются в одну строку;

• каждая препроцессорная лексема преобразуется в лексему языка Си;

Поясним, что понимается под препроцессорными лексемами или лексемами препроцессора (preprocessing token). Можно сказать, что к лексемам препроцессора относятся лексемы языка Си, имена файлов и символы, не определенные иным способом.

Рассмотрим подробно стадию обработки директив препроцессора. При ее выполнении возможны следующие действия:

• замена идентификаторов (обозначений) заранее подготовленными последовательностями символов;

• включение в программу текстов из указанных файлов;

• исключение из программы отдельных частей ее текста (условная компиляция);

• макроподстановка, т.е. замена обозначения параметризованным текстом, формируемым препроцессором с учетом конкретных параметров (аргументов).

Для управления препроцессором используются директивы препроцессора, каждая из которых помещается на отдельной строке и начинается с символа #.

Обобщенный формат директивы препроцессора:

#имя_директивы лексемы_препроцессора

Перед символом '#' и после него в директиве разрешены пробелы. Пробелы также разрешены перед лексемами_препроцессора, между ними и после них. Окончанием препроцессорной директивы служит конец текстовой строки (при наличии символа '\', обозначающего перенос строки, окончанием препроцессорной директивы будет признак конца следующей строки текста).

Определены следующие препроцессорные директивы:

#define - определение макроса или препроцессорного идентификатора;

#undef - отмена определения макроса или идентификатора (препроцессорного);

#include - включение текста из файла;

#if - проверка условия-выражения;

#else - начало альтернативной ветви для #if;

#elif - составная директива #else/#if;

#endif - окончание условной директивы #if;

#ifdef - проверка определенности идентификатора;

#ifndef - проверка неопределенности идентификатора;

#line - смена номера следующей ниже строки;

#error - формирование текста сообщения об ошибке трансляции;

#pragma - действия, предусмотренные реализацией;

# - пустая директива.

Кроме препроцессорных директив имеются три препроцессорных оператора, которые будут рассмотрены вместе с командой #define:

defined - проверка истинности операнда;

## - конкатенация препроцессорных лексем;

# - преобразование операнда в строку символов.

Директива #define имеет несколько модификации. Они предусматривают определение макросов и препроцессорных идентификаторов, каждому из которых ставится в соответствие некоторая символьная последовательность.

Директива #undef отменяет действие директивы #define, которая определила до этого имя препроцессорного идентификатора.

Директива #include позволяет включать в текст программы текст из указанного файла.

Директива #if и ее модификации #ifdef, #ifndef совместно с директивами #else, #endif, #elif позволяют организовать условную обработку текста программы. При использовании этих средств компилируется не весь текст, а только те его части, которые выделены с помощью перечисленных директив.

Директива #line позволяет управлять нумерацией строк в файле с программой. Имя файла и желаемый начальный номер строки указываются непосредственно в директиве #line (подробнее позже).

Директива #error позволяет задать текст диагностического сообщения, которое выводится при возникновении ошибок.

Директива #pragma вызывает действия, зависящие от реализации, т.е. запланированные авторами компилятора.

Директива # ничего не вызывает, так как является пустой ди-рективои, т.е. не дает никакого эффекта и всегда игнорируется.

Рассмотрим возможности перечисленных директив.