Читать «C++: базовый курс» онлайн - страница 332

Herbert Schildt

Как директива #ifdef, так и директива #ifndef может иметь директиву #else или #elif. Рассмотрим пример.

#include <iostream>

using namespace std;

#define TOM

int main()

{

 #ifdef TOM

  cout << "Программист Том.\n";

 #else

  cout << "Программист неизвестен.\n";

 #endif

 #ifndef RALPH

  cout << "Имя RALPH не определено.\n";

 #endif

 return 0;

}

При выполнении эта программа отображает следующее.

Программист Том.

Имя RALPH не определено.

Но если бы идентификатор ТОМ был не определен, то результат выполнения этой программы выглядел бы так.

Программист неизвестен.

Имя RALPH не определено.

И еще. Директивы #ifdef и #ifndef можно вкладывать точно так же, как и директивы #if.

Директива #undef

Директива #undef используется для удаления предыдущего определения некоторого макроимени. Ее общий формат таков.

#undef макроимя

Рассмотрим пример.

#define TIMEOUT 100

#define WAIT 0

 // . . .

#undef TIMEOUT

#undef WAIT

Здесь имена TIMEOUT и WAIT определены до тех пор, пока не выполнится директива #undef.

Основное назначение директивы #undef — разрешить локализацию макроимен для тех частей кода, в которых они нужны.

Использование оператора defined

Помимо директивы #ifdef существует еще один способ выяснить, определено ли в программе некоторое макроимя. Для этого можно использовать директиву #if в сочетании с оператором времени компиляции defined. Например, чтобы узнать, определено ли макроимя MYFILE, можно использовать одну из следующих команд препроцессорной обработки.

#if defined MYFILE

или

#ifdef MYFILE

При необходимости, чтобы реверсировать условие проверки, можно предварить оператор defined символом "!". Например, следующий фрагмент кода скомпилируется только в том случае, если макроимя DEBUG не определено.

#if !defined DEBUG

 cout << "Окончательная версия!\n";

#endif

О роли препроцессора

Препроцессор C++ — прямой потомок препроцессора языка С, причем без каких-либо усовершенствований. Однако его роль в C++ намного меньше роли, которую играет препроцессор в С. Дело в том, что многие задачи, выполняемые препроцессором в С, реализованы в C++ в виде элементов языка. Страуструп тем самым выразил свое намерение сделать функции препроцессора ненужными, чтобы в конце концов от него можно было бы совсем освободить язык.

На данном этапе препроцессор уже частично избыточен. Например, два наиболее употребительных свойства директивы #define были заменены инструкциями C++. В частности, ее способность создавать константное значение и определять макроопределение, действующее подобно функциям, сейчас совершенно избыточна. В C++ есть более эффективные средства для выполнения этих задач. Для создания константы достаточно определить const-переменную. А с созданием встраиваемой (подставляемой) функции вполне справляется спецификатор inline. Оба эти средства лучше работают, чем соответствующие механизмы директивы #define.

Приведем еще один пример замены элементов препроцессора элементами языка. Он связан с использованием однострочного комментария. Одна из причин его создания — разрешить "превращение" кода в комментарий. Как вы знаете, комментарий, использующий /*...*/-стиль, не может быть вложенным. Это означает, что фрагменты кода, содержащие /*...*/-комментарии, одним махом "превратить в комментарий" нельзя. Но это можно сделать с //-комментариями, окружив их /*...*/-символами комментария. Возможность "превращения" кода в комментарий делает использование таких директив условной компиляции, как #ifdef, частично избыточным.