logo
Подбельский Фомин_Программирование на языке СИ_

3.3. Включение текстов из файлов

Для включения текста из файла, как мы уже неоднократно показывали, используется команда #include, имеющая три формы записи:

#include < имя_файла > /* Имя в угловых скобках */

#include "имя_файла" /* Имя в кавычках */

#include имя_макроса /* Макрос, расширяемый до обозначения файла*/

где имя_макроса - это введенный директивой #define препроцессорный идентификатор либо макрос, при замене которого после конечного числа подстановок будет получена последовательность символов <имя_файла> либо "имя_файла". (О макросах см. ниже в §3.5.)

До сих пор мы в программах и примерах фрагментов программ использовали только первую форму команды #include. Существует правило, что если имя_файла - в угловых скобках, то препроцессор разыскивает файл в стандартных системных каталогах. Если имя_фата заключено в кавычки, то вначале препроцессор просматривает текущий каталог пользователя и только затем обращается к просмотру стандартных системных каталогов.

Начиная работать с языком Си, пользователь сразу же сталкивается с необходимостью использования в программах средств ввода-вывода. Для этого в начале текста программы помещают директиву:

#include <stdio.h>

Выполняя эту директиву, препроцессор включает в программу средства связи с библиотекой ввода-вывода. Поиск файла stdio.h ведется в стандартных системных каталогах.

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

Кроме такого в некоторой степени стандартного файла, каким является stdio.h, в заголовок программы могут быть включены любые другие файлы (стандартные или подготовленные специально). Перечень обозначений заголовочных файлов для работы с библиотеками компилятора утвержден стандартом языка. Ниже приведены названия этих файлов, а также краткие сведения о тех описаниях и определениях, которые в них включены. Большинство описаний - прототипы стандартных функций, а определены в основном константы (например, NULL, EOF), необходимые для работы с библиотечными функциями. Все имена, определенные в стандартных заголовочных файлах, являются зарезервированными именами:

assert.h - Диагностика программ

ctype.h - Преобразование и проверка символов

errno.h - Проверка ошибок

float.h - Работа с вещественными данными

limits.h - Предельные значения целочисленных данных

locate.h - Поддержка национальной среды

math.h - Математические вычисления

setjump.h - Возможности нелокальных переходов

signal.h - Обработка исключительных ситуаций

stdarg.h - Поддержка переменного числа параметров

stddef.h - Дополнительные определения

stdio.li - Средства ввода-вывода

stdlib.h - Функции общего назначения (работа с памятью)

string.h - Работа со строками символов

time.h - Определение дат и времени

В конкретных реализациях количество и наименования заголовочных файлов могут быть и другими. Например, в компиляторах для MS-DOS активно используются заголовочные файлы с названиями mem.h, alloc.h, conio.h, dos.h и др. Кроме того, почти в каждой операционной системе имеется библиотека графических функций, для связи с которыми вводится соответствующий заголовочный файл. Например, в компиляторах Turbo С и Borland C++ для связи с графической библиотекой применяется заголовочный файл с названием graphics.h.

Стандартные заголовочные файлы могут быть нечаянно или нарочно включены в текст программы в любом порядке и по несколько раз без отрицательных побочных эффектов. Однако действие включаемого заголовочного файла распространяется на текст программы только в пределах одного модуля от места размещения директивы #include и до конца текстового файла (и всех включаемых в программу текстов).

Заголовочные нестандартные файлы оказываются весьма эффективным средством при модульной разработке крупных программ, когда связь между модулями, размещаемыми в разных файлах, реализуется не только с помощью параметров, но и через внешние объекты, глобальные для нескольких или всех модулей. Описания таких внешних объектов (переменных, массивов, структур и т.п.) и прототипы функций помещаются в одном файле, который с помощью директив #include включается во все модули, где необходимы внешние объекты. В тот же файл можно включить и директиву подключения файла с описаниями библиотеки функций ввода-вывода. Заголовочный файл может быть, например, таким:

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

В главе 8 приведены примеры разработки таких программ. Одним из примером служит задача формирования гистограммы с целью оценки последовательности псевдослучайных чисел. При разработке программы выделены шесть функций и введены внешние переменные, которые должны быть доступны для этих функций. Список не главных функций (их прототипы) получился (см. гл. 8) таким:

void count(void);

void estimate (double *, double *, double *);

void compare (double, double);

double gauss (double, double);

int pseudorand (void);

В тексты всех перечисленных функций, а также в функцию main() помещены прототипы вызываемых функций. Кроме того, в каждой функции описаны со спецификатором extern все внешние объекты, доступ к которым нужен в теле функции (о внешних объектах, спецификаторе extern и классах памяти подробно будет говориться в §5.7).

Такое размещение описаний и определений допускает произвольный порядок размещения текстов функций в программном файле. Если в качестве имен файлов с текстами функций программы выбраны идентификаторы, близкие к именам функций, то возможен следующий текст программы (одни процессорные команды):

Имена файлов соответствуют именам функций с добавкой расширения ".с". Единственное исключение - имя файла "pseudo.c". Здесь имя функции pseudorand( ) укорочено, чтобы программа могла выполняться и для реализации под MS-DOS, где имена файлов не должны превышать восьми символов.

Как иллюстрирует этот пример, исходный текст программы может быть настолько сокращен, что будет содержать только директивы препроцессора.

Препроцессор включает настоящие (реальные) тексты всех функций в программу и как единое целое (модуль) передает полученный текст на компиляцию.