Эти директивы позволяют исключить компиляцию отдельных частей программы в зависимости от проверяемого условия (условие – константное выражение).
#if условие текст_для_if [ #elif условие1 текст1 ] [ #elif условие2 текст2 ] ... [ #else текст_для_else ] #endif | Проверяется условие. Если оно истинно (¹0), то в компилируемый текст включается текст_для_if; в противном случае (=0) вычисляется условие1, если оно ложно (=0), вычисляется условие2 и т.д. В компилируемый текст включается текст, соответствующий условию, которое оказалось истинным. Если все условия ложны, то включается текст_для_else (либо ничего не включается в случае отсутствия #else). |
Здесь квадратные скобки означают необязательность элемента синтаксической конструкции.
Таким образом, препроцессор обработает только один текст (либо ни одного), выделенный директивами #if, #elif. Количество директив #elif – произвольное.
Рассмотрим пример с условным включением различных версий заголовочного файла:
#if VER == 1
#define INCFILE "vers1.h"
|
|
#elif VER == 2
#define INCFILE "vers2.h"
... // И так далее
#else
#define INCFILE "vers.h"
#endif
#include INCFILE
Другое назначение директивы #if – временно закоммен тировать фрагмент кода. Поскольку допускается вложенность директив (при недопустимости вложенности многострочных комментариев), такой способ весьма удобен:
#if 0
... // Исключаемый код
#endif
#ifdef идентификатор // текст #endif | Текст включается компилятором, если определён к текущему моменту с помощью #define идентификатор (он является препроцессорным). |
В директиве #ifndef проверяется обратное условие (если идентификатор не определён).
! | Действие директив #ifdef и #ifndef распространяется до первой директивы #elif, #else, #endif. |
Пример включения контрольной печати при отладке:
#define DEBUG
...
#ifdef DEBUG
cout << "Отладочная печать";
#endif
Убрав директиву #define DEBUG, сразу отключаем все отладочные распечатки.
Рассмотрим пример защиты от повторного включения файлов (программа состоит из нескольких модулей, в каждом из которых препроцессорно включается один и тот же заголовочный файл; модули объединяются в общий текст). Аналогом этого использования директив #ifndef... #define... #endif в Microsoft Visual Studio является #pragma once.
// Файл myheader.h
#ifndef MYHEADER_INCLUDED
#define MYHEADER_INCLUDED
... // Текст заголовочного файла
#endif
// Файл file1.cpp
#include "myheader.h"
... // Текст файла file1.cpp
// Файл file2.cpp
#include "myheader.h"
... // Текст файла file2.cpp
Здесь MYHEADER_INCLUDED – зарезервированный для заголовочного файла препроцессорный идентификатор, который должен быть уникальным (не должен встречаться в других текстах многомодульной программы). При первом использовании директивы #include "myheader.h" произойдёт включение текста файла myheader.h, препроцессорный идентификатор MYHEADER_INCLUDED определится директивой #define, и при последующих директивах #include файл повторно вставляться не будет.
|
|
Операция defined – унарная препроцессорная.
Формат использования операции:
defined операнд | или | defined (операнд) |
Выражение – результат операции – истинно, если идентификатор операнда до этого определён директивой #define:
#if defined операнд º #ifdef операнд
Операцию defined добно использовать, например, при сложном условии выбора:
#if defined (A) &&!defined (B) ... #endif | #ifdef A #ifndef B ... #endif #endif |
Текст передаётся компилятору в случае определения идентификатора А как препроцессорного и не определения В.