Заголовочные файлы включаются в текст программы с помощью директивы препроцессора #include. Директивы препроцессора начинаются со знака “диез” (#), который должен быть самым первым символом строки. Программа, которая обрабатывает эти директивы, называется препроцессором (в современных компиляторах препроцессор обычно является частью самого компилятора).
Директива #include включает в программу содержимое указанного файла. Имя файла может быть указано двумя способами:
1 2 |
#include <some_file .h> #include "my_file.h"</some_file> |
Если имя файла заключено в угловые скобки (<>), считается, что нам нужен некий стандартный заголовочный файл, и компилятор ищет этот файл в предопределенных местах. (Способ определения этих мест сильно различается для разных платформ и реализаций.) Двойные кавычки означают, что заголовочный файл - пользовательский, и его поиск начинается с того каталога, где находится исходный текст программы.
Заголовочный файл также может содержать директивы #include. Поэтому иногда трудно понять, какие же конкретно заголовочные файлы включены в данный исходный текст, и некоторые заголовочные файлы могут оказаться включенными несколько раз. Избежать этого позволяют условные директивы препроцессора. Рассмотрим пример:
1 2 3 4 |
#ifndef BOOKSTORE_H #define BOOKSTORE_H /* содержимое файла bookstore.h */ #endif |
Условная директива #ifndef проверяет, не было ли значение BOOKSTORE_H определено ранее. (BOOKSTORE_H - это константа препроцессора; такие константы принято писать заглавными буквами.) Препроцессор обрабатывает следующие строки вплоть до директивы #endif. В противном случае он пропускает строки от #ifndef до # endif.
Директива:
1 |
#define BOOKSTORE_H |
определяет константу препроцессора BOOKSTORE_H. Поместив эту директиву непосредственно после директивы #ifndef, мы можем гарантировать, что содержательная часть заголовочного файла bookstore.h будет включена в исходный текст только один раз, сколько бы раз ни включался в текст сам этот файл.
Другим распространенным примером применения условных директив препроцессора является включение в текст программы отладочной информации. Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
int main() { #ifdef DEBUG cout « "Начало выполнения main()\n"; #endif string word; vector<string> text; while ( cin » word ) { #ifdef DEBUG cout « "Прочитано слово: " « word « "\n"; #endif text.push_back(word); } // ... }</string> |
Если константа DEBUG не определена, результирующий текст программы будет выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 |
int main() { string word; vector<string> text; while ( cin » word ) { text.push_back(word); } // ... }</string> |
В противном случае мы получим:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int main() { cout « "Начало выполнения main()\n"; string word; vector<string> text; while ( cin » word ) { cout « "Прочитано слово: " « word « "\n"; text.push_back(word); } // ... }</string> |
Константа препроцессора может быть определена в командной строке при вызове компилятора с помощью опции -D (в различных реализациях эта опция может называться по-разному). Для UNIX-систем вызов компилятора с определением препроцессорной константы DEBUG выглядит следующим образом:
1 |
$ CC -DDEBUG main.C |
Есть константы, которые автоматически определяются компилятором. Например, мы можем узнать, компилируем ли мы С++ или С программу. Для С++ программы автоматически определяется константа __cplusplus (два подчеркивания). Для стандартного С определяется __STDC__. Естественно, обе константы не могут быть определены одновременно. Пример:
1 2 3 4 5 6 7 8 |
#idfef __cplusplus // компиляция С++ программы extern "C"; // extern "C" объясняется в главе 7 #endif int main(int,int); |
Другими полезными предопределенными константами (в данном случае лучше сказать переменными) препроцессора являются __LINE__ и __FILE__. Переменная __LINE__ содержит номер текущей компилируемой строки, а __FILE__ - имя компилируемого файла. Вот пример их использования:
1 2 3 4 |
if ( element_count == 0 ) cerr « "Ошибка. Файл: " « __FILE__ « " Строка: " « __LINE__ « "element_count не может быть 0"; |
Две константы __DATE__ и __TIME__ содержат дату и время компиляции.
Стандартная библиотека С предоставляет полезный макрос assert, который проверяет некоторое условие и в случае, если оно не выполняется, выдает диагностическое сообщение и аварийно завершает программу. Мы будем часто пользоваться этим полезным макросом в последующих примерах программ. Для его применения следует включить в программу директиву
1 |
#include <assert .h></assert> |
assert.h - это заголовочный файл стандартной библиотеки С. Программа на C++ может ссылаться на заголовочный файл как по его имени, принятому в C, так и по имени, принятому в C++. В стандартной библиотеке С++ этот файл носит имя cassert.
Имя заголовочного файла в библиотеке С++ отличается от имени соответствующего файла для С отсутствием расширения .h и подставленной спереди буквой c (выше уже упоминалось, что в заголовочных файлах для C++ расширения не употребляются, поскольку они могут зависеть от реализации).
Эффект от использования директивы препроцессора #include зависит от типа заголовочного файла. Инструкция:
1 |
#include <cassert></cassert> |
включает в текст программы содержимое файла cassert. Но поскольку все имена, используемые в стандартной библиотеке С++, определены в пространстве std, имя assert будет невидимо до тех пор, пока мы явно не сделаем его видимым с помощью следующей using-директивы:
1 |
using namespace std; |
Если же мы включаем в программу заголовочный файл для библиотеки С
1 |
#include <assert .h></assert> |
то надобность в using-директиве отпадает: имя assert будет видно и так . (Пространства имен используются разработчиками библиотек для предотвращения засорения глобального пространства имен.