Просмотр промежуточного файла

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

Использование директивы #define

Команда #define определяет строку подстановки. Строка

#define BIG 512

означает, что вы предписываете препроцессору заменять лексему BIG строкой 512 в любом месте программы. Эта запись не является командой языка C++. Строка 512 вставляются в исходную программу везде, где встречается лексема BIG. Лексема — это строка символов, которую можно применить там, где может использоваться любая строка, константа или какой-нибудь другой набор символов. Таким образом, при записи строк

#define BIG 512 int myArray[BIG];

промежуточный файл, создаваемый препроцессором, будет иметь такой вид:

int myArray[512];

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

Использование директивы #define для создания констант

Один вариант использования директивы #define - это создание констант. Однако этим не стоит злоупотреблять, поскольку директива #define просто выполняет замену строки и не осуществляет никакого контроля за соответствием типов. Как пояснялось на занятии, посвященном константам, гораздо безопаснее вместо директивы #define использовать ключевое слово const.

Использование директивы #define для тестирования

Второй способ использования директивы #define состоит в простом объявлении того, что данная лексема определена в программе. Например, можно записать следующее:

#define BIG

В программе можно проверить, была ли определена лексема BIG, и предпринять соответствующие меры. Для подобной проверки используются такие команды препроцессора, как #ifdef (если определена) и #ifndef (если не определена). За обеими

командами должна следовать команда #endif, которую необходимо установить до завершения блока (до следующей закрывающей фигурной скобки).

Директива #ifdef принимает значение, равное истине, если тестируемая лексема уже была определена. Поэтому можем записать следующее:

#ifdef DEBUG

cout << "Строка DEBUG определена"; #endif

Когда препроцессор читает директиву #ifdef, он проверяет построенную им самим таблицу, чтобы узнать, была ли уже определена в программе лексема DEBUG. Если да, то #ifdef возвращает значение true, и все, что находится до следующей директивы #else или #endif, записывается в промежуточный файл для компиляции. Если эта директива возвращает значение false, то ни одна строка кода, находящаяся между директивами #ifdef DEBUG и #endif, не будет записана в промежуточный файл, т.е. вы получите такой вариант промежуточного файла, как будто этих строк никогда и не было в исходном коде.

Обратите внимание, что директива #ifndef является логической противоположностью директивы #ifdef. Директива #ifndef возвращает true в том случае, если до этой точки в программе заданная лексема не была определена.

Комманда препроцессора #else

Как вы правильно предположили, директиву #else можно вставить между #ifdef (или #ifndef) и завершающей директивой #endif. Использование этих директив показано в листинге 21.1.

Листинг 21.1. Использование директивы #define

1: #define DemoVersion

2: #define NT_VERSION 5

3: #include <iostream.h>

4:

5:

6: int main()

7: {

8:

9: cout << "Checking on the definitions of DemoVersion, NT_VERSION _and WINDOWS_VERSION...\n";

10:

11: #ifdef DemoVersion

12: cout << "DemoVersion defined.\n";

13: #else

14: cout << "DemoVersion not defined.\n";

15: #endif

16:

17: #ifndef NT_VERSION

18: cout << "NT_VERSION not defined!\n";

19: #else

20: cout << "NT_VERSION defined as: " << NT_VERSION << endl;

21: #endif

22:

23: #ifdef WINDOWS_VERSION

24: cout << "WINDOWS_VERSION definod!\n";

25: #else

26: cout << "WINDOWS_VERSION was nol: do1inod.\n";

27: #endif

28:

29: cout << "Done.\n";

30: return 0;

31: }

Результат:

hecking on the definitions of DemoVersion, NT_VERSION_and

WINDOWS_VERSION...

DemoVersion defined.

NT_VERSION defined as: 5

WINDOWS_VERSION was not defined.

Done.

Анализ: В строках 1 и 2 определяются лексемы DemoVersion и NT_VERSION, причем лексеме NT_VERSION назначается литерал 5. В строке 11 проверяется определение лексемы DemoVersion, а поскольку она определена (хотя и без значения), то результат тестирования принимает истинное значение и строка 12 выводит соответствующее сообщение.

В строке 17 определенность лексемы NT_VERSION проверяется с помощью директивы #ifndef. Поскольку данная лексема определена, возвращается значение false и выполнение программы продолжается со строки 20. Именно здесь слово NT_VERSION заменяется символом 5, т.е. компилятор воспринимает эту строку кода в следующем виде:

cout << " NT_VERSION defined as: " << 5 << endl:

Обратите внимание, что первое слово в сообщении NT_VERSION не замещается строкой 5, поскольку является частью текстовой строки, заключенной в кавычки. Но лексема NT_VERSION между операторами вывода замешается; таким образом, компилятор видит вместо нее символ 5, точно так же, как если бы вы ввели этот символ в выражение вывода.

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

Наши рекомендации