Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курс лекций по программированию и алгоритмизаци...doc
Скачиваний:
31
Добавлен:
05.09.2019
Размер:
2.24 Mб
Скачать

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

Условная компиляция

Можно избирательно компилировать части файла в зависимости от значения некоторого константного выражения или идентификатора. Для этого служат директивы:

#if, #elif, #else, #endif.

Синтаксис условной конструкции:

#if <выражение1> последовательность операторов //компилировать, если

// <выражение1> истинно.

#elif <выражение2> операторы //компилировать, если <выражение1> ложно, а

// <выражение2> истинно

#elif <выражение3> последовательность операторов // компилировать, если

// <выражения1 и 2> ложны, а <выражение3> истинно

#else операторы // компилировать, если все выражения ложны.

#endif // конец для условной компиляции if.

Правило выполнения условных директив.

1. Для каждого #if должна быть соответствующая #endif.

2. Директивы #elif и #else являются опциональными (исключают друг друга).

3. Число директив #elif между #if и #endif не ограничено. Директива #else должна быть одна и находиться перед #endif.

4. Аналогично оператору if ...else компилируется та секция, которая соответс-твует первому истинному выражению.

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

6. Значение выражения должно быть целой константой; в выражении нельзя использовать операцию sizeof и преобразование типов.

Оператор defined или знак операции препроцессора

Он может применяться в директивах #if и #elif и позволяет проверить, был ли определен идентификатор или макрос.

void ShowMessage(char *msg)

{

# if defined(DOS_target)

puts(msg);

# else MessageBox(NULL,msg,''MSG'',MB_OK);

# endif

}

Если макрос DOS_target определен, то функция ShowMessage использует для вывода сообщения функцию puts, в противном случае компилируется функция MessageBox для специального вывода.

Можно применять логическую операцию «!» для проверки того, что иденти-фикатор не определен. Функцию void ShowMessage(DOS_target) можно перепи-сать таким образом:

{ # if !defined(DOS_target)

MessageBox(NULL,msg,''MSG'',MB_OK);

# else

puts(msg);

# endif

}

Директивы #ifdef и #ifndef

Эти директивы эквивалентны соответственно #if defined и #if !defined и позволяют проверить, определен идентификатор в данный момент или нет. Однако применение оператора defined является более предпочтительным, т.к. он позволяет проверить сразу несколько макросов в сложных логических выражениях.

# ifdef DOS_target можно упростить до # if defined (DOS_target)

# ifndef NDEBUG &&!defined(NDEBUG)

puts(msg); puts(msg);

# endif # endif

# endif

Данные директивы требуют наличия соответствующей директивы #endif, между ними может (но не обязательно) размещаться директива #else или #elif.

Директива #error

Позволяет выдавать во время компиляции сообщение об ошибке. Ее структура: #error <сообщение об ошибке>

Сообщение может включать в себя идентификаторы макросов, которые будут расширены препроцессором. Они применяются обычно в случаях, когда не был определен необходимый идентификатор.

Директива #line

Позволяет изменить внутренний счетчик строк компилятора и имеет структуру: #line номер строки["имя файла"]

Номер строки должен быть целой константой. В строке может присутствовать опциональное имя файла. Эта директива изменяет предопределенный макрос _ _LINE_ _. Если присутствует имя файла, то меняется макрос_ _FILE_ _. Директива используется, чтобы в процессе трансляции заменить наименование текущего файла исходного текста программы и/или номер строки этого текста.

Предопределенные макросы

Компилятор автоматически определяет некоторые макросы ANSI. ANSI – официальное название стандарта языка Си, препроцессора и библиотеки поддержки выполнения программы, принятое Американским Национальным институтом Стандартов.

__DATE__ – строка, представляющая дату, когда данный файл обрабатывался препроцессором (форма даты mm dd yyyy).

__FILE__ – строка, представляющая имя текущего файла в двойных кавычках.

__LINE__ – целое, представляющее текущий номер строки.

__STDC__ – значение является константой, равной 1, если установлено соответствие со стандартом ANSI, в противном случае макрос не определен.

__TIME__ – строка, представляющая время в форме hh:mm:ss, когда данный файл обрабатывался препроцессором.

Директива #pragma

Позволяет управлять специфическими возможностями компилятора. Ее синтаксис: #pragma <директива>

Если реализация системы программирования, обнаружив pragma, ее не узнает, то система ее игнорирует. (Стандартных прагм не существует).

Директивы #pragma, поддерживаемые компилятором C++:

аrgsusd подавляет предупреждающее сообщение о том, что параметр xхх не использован для функции, следующей за директивой;

exit – позволяет указать функцию, которая должна быть вызвана перед завершением программы;

еxtref – заставляет компилятор включить ссылку на неиспользованную внешнюю переменную или функцию;

hdrfile – специфицирует имя заранее откомпилированного файла-заголовка;

hdrignore – т.к. макросы и типы, определяемые в заголовочном файле, могут изменяться, когда определяется другой макрос, компилятор не использует информацию из перекомпилированного заголовка, если встречает директиву условной компиляции. Данная директива указывает, что заголовок должен использоваться, если встречается в директиве условной компиляции;

hdrstop – предписывает компилятору не включать дальнейшую информацию, перекомпилированную в заголовочный файл;

inline – указывает, что компиляция текущего модуля должна производиться через ассемблер;

intrinsic – эта директива может быть использована, чтобы разрешить или запретить генерацию inline-кода для встроенной функции; (встроенная функция – это библиотечная процедура, для которой компилятор генерирует inline-код вместо вызова библиотеки);

obsolete – приводит к тому, что компилятор генерирует сообщение-предупреж-дение о том, что имя файла является устаревшей функцией. Ее можно использовать, чтобы сообщить другим программистам, что улучен код и предусмотрена для данной задачи новая функция;

option – позволяет включить в код опции командной строки компилятора;

startup – является дополнительной к #pragma exit, позволяет указать функцию, которая должна выполняться до функции main;

warn – позволяет выборочно разрешать или подавлять предупреждающее сообщение. Если предупреждению предшествует знак «+», то выдача сообщения разрешается, если знак «-» , то запрещается.

Некоторые компиляторы, в частности ANSI, узнают директиву pragma, которая указывает на то, как плотно упакованы смежные члены в структуру, например: #pragma pack (n) , где n может быть 1,2 или 4, указывая, что имеет место выравнивание на границу байта, слова или двойного слова.

В языке С/С++ имеются также директивы подключения библиотек # include и макроподстановок #define.