Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на C / C++ / Основы программирования на Си.doc
Скачиваний:
361
Добавлен:
02.05.2014
Размер:
1.3 Mб
Скачать

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

Командные строки препроцессора используются для условной компиляции различных частей исходного текста в зависимости от внешних условий.

#if константное_выражение

Пример:

#if ABC + 3

Истина, если константное выражение ABC + 3 не равно нулю.

#ifdef идентификатор

Пример:

#ifdef ABC

истина, если идентификатор ABC определен ранее командой #define.

#ifndef идентификатор

Пример:

#ifndef ABC

истина, если идентификатор ABC не определен в настоящий момент.

#else

. . .

#endif

Если предшествующие проверки #if, #ifdef или #ifndef дают значение "Истина", то строки от #else до #endif игнорируются при компиляции.

Если эти проверки дают значение "Ложь", то строчки от проверки до #else (а при отсутствии #else - до #endif) игнорируются.

Команда #endif обозначает конец условной компиляции.

Пример:

#ifdef DEBUG

fprintf (stderr, "location: x = %d\n", x);

#endif

Вспомогательные директивы

Номер строки и имя файла

#line целая_константа "имя_файла"

Пример:

#line 20 "ABC"

Препроцессор изменяет номер текущей строки и имя компилируемого файла. Имя файла может быть опущено.

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

Пример:

#define N 3/*определение константы */

void main( )

{

#line 55 "file.c"

double x[3*N];

}

Реакция на ошибки

#error последовательность лексем

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

Пример:

#define NAME 15

В дальнейшем можно проверить ее значение и выдать сообщение, если у NAME окажется другое значение:

#if (NAME !=15)

#error NAME должно быть равно 15!

Сообщение будет выглядеть так:

error <имя_файла><номер_строки >;

error directive: NAME должно быть равно 15!

Пустая директива

#

Использование этой директивы не вызывает никаких действий.

Прагмы

#pragma

Эта директива определяет действия, зависящие от конкретной реализации компилятора. Например в некоторые компиляторы входит вариант этой директивы для извещения компилятора о наличии в тексте программы команд на языке Ассемблер. Возможности команды #pragma могут быть разнообазными. Стандарта для них не существует. Если конкретный препроцессор встречает прагму, которая ему неизвестна, он ее просто игнорирует как пустую директиву. В некоторых реализациях включена прагма.

#pragma pack(n), где n= 1,2,4. Прагма pack позволяет влиять на упаковку смежных элементов в структурах и объединениях (см. лекцию 14).

Соглашение может быть таким:

pack(1) - выравнивание элементов по границам байтов;

pack(2) - выравнивание элементов по границам слов;

pack(4) - выравнивание элементов по границам двойных слов;

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

Встроенные макроимена

Существуют встроенные (заранее определенные) макроимена, доступные препроцессору во время обработки. Они позволяют получить следующую информацию:

_DATA_ - строка символов в формате: "месяц число год", определяющая дату начала обработки исходного файла. Например, после препроцессорной обработки текста программы, выполненной 29 января 2005 года, оператор

printf(_DATA_);

станет таким

printf("January 29 2005");

_LINE_ - десятичная константа - номер текущей обрабатываемой строки файла с программой на Си. Принято, что номер первой строки исходного файла равен 1;

_FILE_ - строка символов - имя компилируемого файла. Имя изменяется всякий раз, когда препроцессор встречает директиву #include с указанием имени другого файла. Когда включения файла по команде #include завершаются, востанавливается предыдущее значение макроимени _FILE_;

_TIME_ - строка символов вида "часы:минуты:секунды", определяющая время начала обработки препроцессором исходного файла;

_STDC_ - константа, равная 1, если компилятор работает в соответствии с ANSI-стандартом. В противном случае значение микроимени _STDC_ не определено. Стандарт языка Си предполагает, что наличие имени _STDC_ определяется реализацией, так как макрос _STDC_ относится к нововведениям стандарта. В конкретных реализациях набор предопределенных имен гораздо шире. Для получения более полных сведений о предопределенных препроцессорных именах следует обращаться к документации по конкретному компилятору.