Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Керниган, Ричи. Язык C.docx
Скачиваний:
5
Добавлен:
05.05.2019
Размер:
377.71 Кб
Скачать

* 7. Ввод и вывод *

Средства ввода/вывода не являются составной частью языка

"с", так что мы не выделяли их в нашем предыдущем изложении.

Однако реальные программы взаимодействуют со своей окружаю-

щей средой гораздо более сложным образом, чем мы видели до

сих пор. В этой главе будет описана "стандартная библиотека

ввода/вывода", то есть набор функций, разработанных для

обеспечения стандартной системы ввода/вывода для "с"- прог-

рамм. Эти функции предназначены для удобства программного

интерфейса, и все же отражают только те операции, которые

могут быть обеспечены на большинстве современных операцион-

ных систем. Процедуры достаточно эффективны для того, чтобы

пользователи редко чувствовали необходимость обойти их "ради

эффективности", как бы ни была важна конкретная задача. И,

наконец, эти процедуры задуманы быть "переносимыми" в том

смысле, что они должны существовать в совместимом виде на

любой системе, где имеется язык "с", и что программы, кото-

рые ограничивают свои взаимодействия с системой возможностя-

ми, предоставляемыми стандартной библиотекой, можно будет

переносить с одной системы на другую по существу без измене-

ний.

Мы здесь не будем пытаться описать всю библиотеку вво-

да/вывода; мы более заинтересованы в том, чтобы продемонст-

рировать сущность написания "с"-программ, которые взаимодей-

ствуют со своей операционной средой.

7.1. Обращение к стандартной библиотеке

Каждый исходный файл, который обращается к функции из

стандартной библиотеки, должен вблизи начала содержать стро-

ку

#INCLUDE <STDIO.H>

в файле STDIO.H определяются некоторые макросы и переменные,

используемые библиотекой ввода/вывода. Использование угловых

скобок вместо обычных двойных кавычек - указание компилятору

искать этот файл в справочнике, содержащем заголовки стан-

дартной информации (на системе UNIX обычно LUSRLINELUDE).

Кроме того, при загрузке программы может оказаться необ-

ходимым указать библиотеку явно; на системе PDP-11 UNIX,

например, команда компиляции программы имела бы вид:

CC исходные файлы и т.д. -LS

где -LS указывает на загрузку из стандартной библиотеки.

7.2. Стандартный ввод и вывод - функции getchar и putchar

Самый простой механизм ввода заключается в чтении по од-

ному символу за раз из "стандартного ввода", обычно с терми-

нала пользователя, с помощью функции GETCHAR. Функция

GETCHAR() при каждом к ней обращении возвращает следующий

вводимый символ. В большинстве сред, которые поддерживают

язык "с", терминал может быть заменен некоторым файлом с по-

мощью обозначения < : если некоторая программа PROG исполь-

зует функцию GETCHAR то командная строка

PROG<INFILE

приведет к тому, что PROG будет читать из файла INFILE, а не

с терминала. Переключение ввода делается таким образом, что

сама программа PROG не замечает изменения; в частности стро-

ка"<INFILE" не включается в командную строку аргументов в

ARGV. Переключение ввода оказывается незаметным и в том слу-

чае, когда вывод поступает из другой программы посредством

поточного (PIPE) механизма; командная строка

OTHERPROG \! PROG

прогоняет две программы, OTHERPROG и PROG, и организует так,

что стандартным вводом для PROG служит стандартный вывод

OTHERPROG.

Функция GETCHAR возвращает значение EOF, когда она попа-

дает на конец файла, какой бы ввод она при этом не считыва-

ла. Стандартная библиотека полагает символическую константу

EOF равной -1 (посредством #DEFINE в файле STDIO.H), но про-

верки следует писать в терминах EOF, а не -1, чтобы избежать

зависимости от конкретного значения.

Вывод можно осуществлять с помощью функции PUTCHAR(C),

помещающей символ 'с' в "стандартный ввод", который по умол-

чанию является терминалом. Вывод можно направить в некоторый

файл с помощью обозначения > : если PROG использует PUTCHAR,

то командная строка

PROG>OUTFILE

приведет к записи стандартного вывода в файл OUTFILE, а не

на терминал. На системе UNIX можно также использовать поточ-

ный механизм. Строка

PROG \! ANOTHERPROG

помещает стандартный вывод PROG в стандартный ввод

ANOTHERPROG. И опять PROG не будет осведомлена об изменении

направления.

Вывод, осуществляемый функцией PRINTF, также поступает в

стандартный вывод, и обращения к PUTCHAR и PRINTF могут пе-

ремежаться.

Поразительное количество программ читает только из одно-

го входного потока и пишет только в один выходной поток; для

таких программ ввод и вывод с помощью функций GETCHAR,

PUTCHAR и PRINTF может оказаться вполне адекватным и для на-

чала определенно достаточным. Это особенно справедливо тог-

да, когда имеется возможность указания файлов для ввода и

вывода и поточный механизм для связи вывода одной программы

с вводом другой. Рассмотрим, например, программу LOWER, ко-

торая преобразует прописные буквы из своего ввода в строч-

ные:

#INCLUDE <STDIO.H>

MAIN() /* CONVERT INPUT TO LOWER CASE */

\(

INT C;

WHILE ((C = GETCHAR()) != EOF)

PUTCHAR(ISUPPER(C) ? TOLOWER(C) : C);

\)

"Функции" ISUPPER и TOLOWER на самом деле являются макроса-

ми, определенными в STDIO.H . Макрос ISUPPER проверяет, яв-

ляется ли его аргумент буквой из верхнего регистра, и возв-

ращает ненулевое значение, если это так, и нуль в противном

случае. Макрос TOLOWER преобразует букву из верхнего регист-

ра в ту же букву нижнего регистра. Независимо от того, как

эти функции реализованы на конкретной машине, их внешнее по-

ведение совершенно одинаково, так что использующие их прог-

раммы избавлены от знания символьного набора.

Если требуется преобразовать несколько файлов, то можно

собрать эти файлы с помощью программы, подобной утилите CAT

системы UNIX,

CAT FILE1 FILE2 ... \! LOWER>OUTPUT

и избежать тем самым вопроса о том, как обратиться к этим

файлам из программы. (Программа CAT приводится позже в этой

главе).

Кроме того отметим, что в стандартной библиотеке вво-

да/вывода "функции" GETCHAR и PUTCHAR на самом деле могут

быть макросами. Это позволяет избежать накладных расходов на

обращение к функции для обработки каждого символа. В главе 8

мы продемонстрируем, как это делается.