1. Работа препроцессора. На этом этапе директивы препроцессора заменяются кодом на языке C++. Чтобы облегчить работу программиста, в исходных кодах существует возможность указывать, какую часть кода надо компилировать, а какую пока не стоит. Есть возможность помещать в исходный код выражения, которые к началу компиляции должны превратиться в константы того или иного типа, есть возможность указывать, что в некое место файла исходного кода должен быть вставлен текст из другого файла. Результатом работы препроцессора является файл, в котором все эти действия выполнены и который можно подавать на вход компилятора.
2. Работа компилятора. Расширенные и преобразованные в соответствии с директивами препроцессора файлы исходного кода подаются на вход компилятора, на выходе которого получаются файлы объектного кода.
3. Работа линковщика. Файлы объектного кода связываются между собой в единый исполняемый файл с расширением. exe.
В общем случае за то, какие именно файлы будут обработаны препроцессором, скомпилированы, а потом собраны в исполняемый файл, отвечает специальная программа управления проектами. В большинстве версий языка С++ эта программа носит название make. На вход программы make подается специальный файл (makefile), в котором описывается состав проекта, опции препроцессора, компилятора и линковщика для каждой единицы компиляции, список доступных каталогов и прочие необходимые сведения. В случае eVC все стадии создания файла программы от работы препроцессора до линковки обычно не видны разработчику. Он лишь выполняет команду Build или Execute из пункта меню Build, и весь процесс выполняется за один шаг. Тем не мене в реальности «за ширмой» среды выполняются все этапы, и в качестве файла конфигурации проекта выступает файл с расширением. vcp.
Препроцессор и заголовочные файлы
Файлы заголовков
Файлы заголовков предназначены для хранения определений, которые одновременно применяются в нескольких единицах компиляции, и для объявления имен, которые должны быть видимы более чем в одном модуле программы. В файлах заголовков также объявляются имена и функции, реализация которых находится в бинарных файлах. Использование заголовочных файлов сокращает размер исходных текстов программы, поскольку в сами файлы исходных текстов вставляются только ссылки на заголовочные файлы (при помощи директивы #include). Эти ссылки заменяются текстом заголовочного файла в процессе работы препроцессора.
Какая информация может быть помещена в файлы заголовков? Строго говоря, разработчик может помещать в эти файлы любую информацию, поскольку сами файлы после работы препроцессора просто вставляются в основной файл на место директивы #include. Список хранящихся в этих файлах данных приведен ниже.
1. Объявления функций, которые могут быть использованы в нескольких модулях.
2. Описания классов.
3. Описания внешних переменных.
4. Определения макросов.
5. Определения типов, доступных для всего проекта.
Использование заголовочных файлов и функционирование препроцессора тесно связаны. Какие же директивы для управления работой препроцессора могут быть включены в исходные файлы и в файлы заголовков? Это показано в следующем примере.
Упражнение 4.7
1. Создать простое приложение и сохранить его с именем AdvancedCPP.
2. На вкладке FileView отыскать файл newres.h и двойным щелчком открыть его в редакторе кода. Поскольку этот файл содержит в себе множество директив препроцессора, он послужит хорошей иллюстрацией к их описанию.
Директива #include задает включение в текст данного файла текста другого файла, имя которого указано после директивы. В файле newres.h есть несколько директив #include.
#include
Выполнение этой инструкции приведет к тому, что перед компиляцией в этом месте в текст файла newres.h будет включен текст файла commctrl.h, но только для подачи на вход компилятору. Текст файла newres.h, хранимый на диске, изменен не будет.
Директива #define используется для создания символических констант, для определения макрофункций и для определения управляющего идентификатора.
3. Найти в редакторе кода следующую строку:
#define AFXCE_IDR_SCRATCH_SHMENU 28700
Эта строка создает символическую константу AFXCE_IDR_SCRATCH_SHMENU со значением 28700. Теперь компилятор, обнаружив в тексте программы имя AFXCE_ IDR_SCRATCH_SHMENU, будет вместо него подставлять значение 28700. 4. Открыть в окне FileView файл aygshell.h. В этом файле нужно найти следующую строку кода:
#define CEM_UPCASEALLWORDS (WM_USER + 1)
Читать дальше
Конец ознакомительного отрывка
Купить книгу