• Объявления функций. Заголовочный файл string.h (strings.h в некоторых более старых системах), например, содержит объявления для семейства функций обработки строк. Согласно ANSI С и последующим стандартам, эти объявления представлены в виде прототипов функций.
• Определения шаблонов структур. Стандартные функции ввода-вывода используют структуру FILE, содержащую информацию о файле и связанном с ним буфере. Объявление этой структуры находится в файле stdio.h.
• Определения типов. Вы можете вспомнить, что стандартные функции ввода- вывода применяют аргумент типа указателя на FILE. Обычно в файле stdio.h используется #define или typedef для того, чтобы имя FILE представляло указатель на структуру. Аналогично, в заголовочных файлах определены типы
size_t и time_t.
Многие программисты разрабатывают собственные стандартные заголовочные файлы для применения в своих программах. Это особенно полезно в ситуации, когда вы создаете семейство взаимосвязанных функций и/или структур.
Кроме того, заголовочные файлы можно применять для объявления внешних переменных, с которыми совместно работают несколько файлов. Это целесообразно, например, при разработке семейства функций, совместно использующих переменную для сообщения о некотором состоянии, таком как условие ошибки. В таком случае можно определить переменную с внешним связыванием и областью действия на уровне файла исходного кода, который содержит объявления функций:
int status =0; // переменная с областью действия
// на уровне файла исходного кода
Затем в заголовочный файл, связанный с файлом исходного кода, можно поместить ссылочное объявление:
extern int status; //в заголовочном файле
678 глава 16
Этот код затем появляется в любом файле, в котором был включен данный заголовочный файл, делая переменную доступной файлам, работающим с упомянутым семейством функций. Кроме того, посредством включения это объявление обнаруживается в файле исходного кода функций, однако одном файле допускается наличие определяющего и ссылочного объявлений, если они согласованы по типу.
Еще одним кандидатом для включения в заголовочный является переменная или массив с областью действия на уровне файла, внутренним связыванием и квалификатором const. Часть const предотвращает случайные изменения, а часть static означает, что каждый файл, включающий этот заголовок, получает собственную копию констант. Это устраняет необходимость в наличии одного файла с определяющим объявлением и остальных файлов со ссылочными объявлениями.
Директивы #include и #define являются наиболее интенсивно применяемыми средствами препроцессора С. Остальные директивы будут рассматриваться менее детально.
Другие директивы
Программистам часто приходится создавать программы и библиотечные пакеты на языке С, которые должны работать в разнообразных средах. Виды кода могут варьироваться от среды к среде. Препроцессор предлагает несколько директив, помогающих программисту создавать код, который может переноситься из одной системы в другую за счет изменения значений макросов #def ine. Директива #undef отменяет предыдущее определение #define. Директивы #if, #ifdef, #ifndef, #else, #elif и #endif позволяют указывать различные варианты кода, подлежащего компиляции. Директива #line дает возможность переустанавливать информацию о строках и файлах, директива #error служит для вывода сообщений об ошибках, а с помощью директивы #pragma можно предоставлять инструкции компилятору.
Директива #undef
Директива #undef отменяет заданное определение #define. Предположим, что есть следующее определение:
#define LIMIT 400
1'огда директива
#undef LIMIT
удалит это определение. Затем LIMIT можно переопределить, назначив новое значение. Отмена определения LIMIT допустима даже в случае, если предварительное определение не делалось. Если вы хотите использовать некоторое имя, но не уверены в том, что оно не было определено ранее, на всякий случай его определение можно отменить.
Определение с точки зрения препроцессора
В отношении того, что считать идентификатором, препроцессор следует таким же правилам, как и язык С: идентификатор может состоять только из букв верхнего и нижнего регистра, цифр и символа подчеркивания, а первым символом не может быть цифра. Когда препроцессор встречает в какой-то директиве идентификатор, он считает его определенным или неопределенным. При этом определенный означает, что идентификатор определен препроцессором. Если идентификатор является именем макроса, созданного ранее директивой #define в том же файле, и он не отменялся
Читать дальше