|
Ввод и вывод
7. Ввод и вывод
Средства ввода/вывода не являются составной частью языка "с", так что мы не выделяли их в нашем предыдущем изложении. Однако реальные программы взаимодействуют со своей окружающей средой гораздо более сложным образом, чем мы видели до сих пор. В этой лекции будет описана " стандартная библиотека ввода/вывода ", то есть набор функций, разработанных для обеспечения стандартной системы ввода/вывода для "с"- программ. Эти функции предназначены для удобства программного интерфейса, и все же отражают только те операции, которые могут быть обеспечены на большинстве современных операционных систем. процедуры достаточно эффективны для того, чтобы пользователи редко чувствовали необходимость обойти их "ради эффективности", как бы ни была важна конкретная задача. И, наконец, эти процедуры задуманы быть "переносимыми" в том смысле, что они должны существовать в совместимом виде на любой системе, где имеется язык "с", и что программы, которые ограничивают свои взаимодействия с системой возможностями, предоставляемыми стандартной библиотекой, можно будет переносить с одной системы на другую по существу без изменений.
Мы здесь не будем пытаться описать всю библиотеку ввода/вывода ; мы более заинтересованы в том, чтобы продемонстрировать сущность написания "с"- программ, которые взаимодействуют со своей операционной средой.
7.1. Обращение к стандартной библиотеке
Каждый исходный файл, который обращается к функции из стандартной библиотеки, должен вблизи начала содержать строку
#include <stdio.h>
в файле stdio.h определяются некоторые макросы и переменные, используемые библиотекой ввода/вывода. Использование угловых скобок вместо обычных двойных кавычек - указание компилятору искать этот файл в справочнике, содержащем заголовки стандартной информации (на системе UNIX обычно /usr/include ).
Кроме того, при загрузке программы может оказаться необходимым указать библиотеку явно; на системе 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" мы продемонстрируем, как это делается.