Почти все разработчики, использующие Visual C++, сталкиваются с файлом stdafx.h, в который можно положить много-много различных директив препроцессора. И так мало понимают, зачем это нужно и как с этим работать...
Precompiled Header
Вы, наверное, слышали о понятии Precompiled Header
. Precompiled Header
- это механизм, позволяющий компиляторам сократить время сборки приложения путем прекомпиляции
редко меняющихся файлов исходного кода приложения. В первую очередь - это библиотечный код, точнее заголовочные файлы.
Рассмотрим программу Hello World
:
#include <tchar.h>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[]) {
std::cout << "Hello World!" << std::endl;
return 0;
}
А теперь внимание: после обработки этого файла прекомпилятором, его размер возрастает до 996 килобайт! Я повторюсь: 996 килобайт, из которых 854 составляют полезный код (остальное - комментарии), а размер рабочего кода программы - аж 142 байта. Похоже, для компиляции нашего простейшего cpp-файла компилятору прийдется изрядно потрудиться. Причем над каждым cpp-файлом проекта.
Естественно, лучше предварительно обработать неизменящиеся куски кода, превратив их в удобный и быстрый формат для последующей обработки в составе исходного кода приложения. Компиляторы Visual C++ и GCC поддерживают такую обработку и она носит имя Precompiled Header
.
Использование Precompiled Header в Visual C++
Мастер создания проекта Visual C++ предлагает свои услуги по настройке Precompiled Header. В простейшем случае, среда дает разработчику возможность выбора - использовать этот механизм или нет. В большинстве случаев использование Precompiled Header настраивается автоматически.
Анализ настроек Precompiled Header мастеров Visual C++
Что же мы получаем при автоматической настройке Precompiled Header средой разработки Visual Studio?
- Заголовочный файл
stdafx.h
В этом файле содержатся, как правило, только директивы препроцессора, подключающие внешние заголовочные файлы.
- cpp-файл
stdafx.cpp
Состоит из единственной директивы #include "stdafx.h" и используется для генерации Precompiled Header. Следующая картинка демонстрирует свойства файла stdafx.cpp, раздел C/C++, подраздел Precompiled Headers:
- Каждый cpp-файл проекта, использующий Precompiled Header, обязан включать этот заголовочный файл соответствующей директивой
#include "stdafx.h"
При этом компилятор игнорирует любой текст до момента включения stdafx.h! А в случае его отсутствия - выдает ошибку fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?
- Использование Precompiled Header установлено на уровне cpp-файлов всего проекта, как показано на картинке:

Настройка Precompiled Header вручную
Опираясь на вышенаписанное, последовательность действий простая:
- Создать файл
CommonIncludes.h
- Создать файл
CommonIncludes.cpp и добавить туда одну строчку - #include "CommonIncludes.h"
- Поменять нужные настройки Precompiled Headers в свойствах файла
CommonIncludes.cpp
- Поменять настройки Precompiled Headers на уровне проекта или на уровне отдельных cpp-файлов
- Добавить
#include "CommonIncludes.h" в начало соответствующих cpp-файлов исходного кода
Продвинутое использование Precompiled Header
Как правило, в stdafx.h, созданный визардом, лепят все, что можно влепить. В результате в каждый cpp-файл включается совершенно ненужный ему контент! Поэтому, логично включать в stdafx.h только наиболее используемые заголовочные файлы.
Директивы прекомпилятора в stdafx.h распостраняются одинаковым образом на все cpp-файлы, включающие данный заголовочный файл. Бывает, необходимо настроить поведение библиотеки (в рамках отдельного cpp-файла или группы таких файлов) путем определения каких-то символов перед включением соответствующего заголовочного файла. Первое, что приходит на ум, - определить эти символы в cpp-файле и еще раз включить заголовочный файо библиотеки. Но, нет, я же писал, что компилятор игнорирует любой исходный код до строчки #include "stdafx.h"! Соответственно, повторное включение заголовочных файлов будет просто проигнорировано. Получается, нужно удалять включения заголовочных файлов библиотек из stdafx.h и добавлять их в каждый отдельный cpp-файл.
Также, проект не ограничен одним Precompiled Header! Вполне можно содзать пару файлов Subsystem1Includes.h, Subsystem1Includes.cpp, отвечающих за отдельный Precompiled Header в рамках некоторой группы файлов исходного кода.
Компилятор Visual C++ имеет ограничение на размер pch-файла. На практике это выглядит следующим образом:
error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm130' or greater
fatal error C1076: compiler limit : internal heap limit reached; use /Zm to specify a higher limit
В таком случае спасет опция компилятора /Zm: 