Условная компиляция
Можно избирательно компилировать части файла в зависимости от значения некоторого константного выражения или идентификатора. Для этого служат директивы:
#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.