Смекни!
smekni.com

IF(ARGC==1) /*NO ARGS; COPY STANDARD INPUT*/

FILECOPY(STDIN);

ELSE

WHILE (--ARGC > 0)

IF ((FP=FOPEN(*++ARGV,”R”))==NULL) \(

PRINTF(“CAT:CAN'T OPEN %\N”,*ARGV);

BREAK;

\) ELSE \(

FILECOPY(FP);

FCLOSE(FP);

\)

\)

FILECOPY(FP) /*COPY FILE FP TO STANDARD OUTPUT*/

FILE *FP;

\(

INT C;

WHILE ((C=GETC(FP)) !=EOF)

PUTC(C, STDOUT);

\)

Указатели файлов STDIN и STDOUT заранее определены в библио-

теке ввода-вывода как стандартный ввод и стандартный вывод;

они могут быть использованы в любом месте, где можно исполь-

зовать объект типа FILE*.они однако являются константами, а

не переменными, так что не пытайтесь им что-либо присваи-

вать.

Функция FCLOSE является обратной по отношению к FOPEN;

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

установленную функцией FOPEN, и высвобождает указатель файла

для другого файла.большинство операционных систем имеют не-

которые ограничения на число одновременно открытых файлов,

которыми может распоряжаться программа. Поэтому, то как мы

поступили в CAT, освободив не нужные нам более объекты, яв-

ляется хорошей идеей. Имеется и другая причина для примене-

ния функции FCLOSE к выходному файлу - она вызывает выдачу

информации из буфера, в котором PUTC собирает вывод. (При

нормальном завершении работы программы функция FCLOSE вызы-

вается автоматически для каждого открытого файла).

·
163 -

7.7. Обработка ошибок - STDERR и EXIT

Обработка ошибок в CAT неидеальна. Неудобство заключает-

ся в том, что если один из файлов по некоторой причине ока-

зывается недоступным, диагностическое сообщение об этом пе-

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

вывод поступает на терминал, но не годится, если вывод пос-

тупает в некоторый файл или через поточный (PIPELINE) меха-

низм в другую программу.

Чтобы лучше обрабатывать такую ситуацию, к программе

точно таким же образом, как STDIN и STDOUT, присоединяется

второй выходной файл, называемый STDERR. Если это вообще

возможно, вывод, записанный в файле STDERR, появляется на

терминале пользователя, даже если стандартный вывод направ-

ляется в другое место.

Давайте переделаем программу CAT таким образом, чтобы

сообщения об ошибках писались в стандартный файл ошибок.

“INCLUDE <STDIO.H>

MAIN(ARGC,ARGV) /*CAT: CONCATENATE FILES*/

INT ARGC;

CHAR *ARGV[];

&bsol;(

FILE *FP, *FOPEN();

IF(ARGC==1) /*NO ARGS; COPY STANDARD INPUT*/

FILECOPY(STDIN);

ELSE

WHILE (--ARGC > 0)

IF((FP=FOPEN(*++ARGV,”R#))==NULL) &bsol;(

PRINTF(STDERR,

“CAT: CAN'T OPEN,%S&bsol;N”, ARGV);

EXIT(1);

&bsol;) ELSE &bsol;(

FILECOPY(FP);

&bsol;)

EXIT(0);

&bsol;)

Программа сообщает об ошибках двумя способами. Диагностичес-

кое сообщение, выдаваемое функцией FPRINTF, поступает в

STDERR и, таким образом, оказывается на терминале пользова-

теля, а не исчезает в потоке (PIPELINE) или в выходном фай-

ле.

Программа также использует функцию EXIT из стандартной

библиотеки, обращение к которой вызывает завершение выполне-

ния программы. Аргумент функции EXIT доступен любой програм-

ме, обращающейся к данной функции, так что успешное или неу-

дачное завершение данной программы может быть проверено дру-

гой программой, использующей эту в качестве подзадачи. По

соглашению величина 0 в качетсве возвращаемого значения сви-

детельствует о том, что все в порядке, а различные ненулевые

значения являются признаками нормальных ситуаций.

· 164 -

Функция EXIT вызывает функцию FCLOSE для каждого откры-

того выходного файла, с тем чтобы вывести всю помещенную в

буферы выходную информацию, а затем вызывает функцию _EXIT.

Функция _EXIT приводит к немедленному завершению без очистки

каких-либо буферов; конечно, при желании к этой функции мож-

но обратиться непосредственно.

7.8. Ввод и вывод строк

Стандартная библиотека содержит функцию FGETS, совершен-

но аналогичную функции GETLINE, которую мы использовали на

всем протяжении книги. В результате обращения

FGETS(LINE, MAXLINE, FP)

следующая строка ввода (включая символ новой строки) считы-

вается из файла FP в символьный массив LINE; самое большое

MAXLINE_1 символ будет прочитан. Результирующая строка за-

канчивается символом &bsol; 0. Нормально функция FGETS возвращает

LINE; в конце файла она возвращает NULL. (Наша функция

GETLINE возвращает длину строки, а при выходе на конец файла

· нуль).

Предназначенная для вывода функция FPUTS записывает

строку (которая не обязана содержать символ новой строки) в

файл:

FPUTS(LINE, FP)

Чтобы показать, что в функциях типа FGETS и FPUTS нет ничего таинственного, мы приводим их ниже, скопированными непосредственно из стандартной библиотеки ввода-вывода:

#INCLUDE <STDIO.H>

CHAR *FGETS(S,N,IOP) /*GET AT MOST N CHARS FROM IOP*/

CHAR *S;

INT N;

REGISTER FILE *IOP;

&bsol;(

REGISTER INT C;

REGISTER CHAR *CS;

CS = S;

WHILE(--N>0&&(C=GETC(IOP)) !=EOF)

IF ((*CS++ = C)=='&bsol;N')

BREAK;

*CS = '&bsol;0';

RETURN((C==EOF && CS==S) 7 NULL : S);

&bsol;)

FPUTS(S,IOP) /*PUT STRING S ON FILS IOP*/

REGISTER CHAR *S;

REGISTER FILE *IOP;

&bsol;(

REGISTER INT C;

WHILE (C = *S++)

PUTC(C,IOP);

&bsol;)

· 165 -

Упражнение 7-3.

Напишите программу сравнения двух файлов, которая будет

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

ся.

Упражнение 7-4.

Переделайте программу поиска заданной комбинации симво-

лов из главы 5 таким образом, чтобы в качестве ввода исполь-

зовался набор именованных файлов или, если никакие файлы не

указаны как аргументы, стандартный ввод. Следует ли печатать

имя файла при нахождении подходящей строки?

Упражнение 7-5.

Напишите программу печати набора файлов, которая начина-

ет каждый новый файл с новой страницы и печатает для каждого

файла заголовок и счетчик текущих страниц.

7.9. Несколько разнообразных функций

Стандартная библиотека предоставляет множество разнооб-

разных функций, некоторые из которых оказываются особенно

полезными. Мы уже упоминали функции для работы со строками:

STRLEN, STRCPY, STRCAT и STRCMP. Вот некоторые другие.

7.9.1. Проверка вида символов и преобразования

Некоторые макросы выполняют проверку символов и преобра-

зования:

SALPHA© не 0, если “C” алфавитный символ,

0 - если нет.

SUPPER© Не 0, если “C” буква верхнего регистра,

0 - если нет.

SLOWER© Не 0, если “C” буква нижнего регистра,

0 - если нет.

SDIGIT© Не 0, если “C” цифра,

0 - если нет.

SSPACL© Не 0, если “C” пробел, табуляция

или новая строка, 0 - если нет.

OUPPER© Преобразует “C” в букву верхнего регистра.

OLOWER© Преобразует “C” в букву нижнего регистра.

7.9.2. Функция UNGETC

Стандартная библиотека содержит довольно ограниченную

версию функции UNGETCH, написанной нами в главе 4; она назы-

вается UNGETC. В результате обращения

UNGETC(C,FP)

символ “C” возвращается в файл FP. Позволяется возвращать в

каждый файл только один символ. Функция UNGETC может быть

использована в любой из функций ввода и с макросами типа

SCANF, GETC или GETCHAR.

· 166 -

7.9.3. Обращение к системе

Функция SYSTEM(S) выполняет команду, содержащуюся в сим-

вольной строке S, и затем возобновляет выполнение текущей

программы. Содержимое S сильно зависит от используемой опе-

рационной системы. В качестве тривиального примера, укажем,

что на системе UNIX строка

SYSTEM(“DATE”);

приводит к выполнению программы DATE, которая печатает дату

и время дня.

7.9.4. Управление памятью

Функция CALLOC весьма сходна с функцией ALLOC, использо-

ванной нами в предыдущих главах. В результате обращения

CALLOC(N, SIZEOF(OBJCCT))

возвращается либо указатель пространства, достаточного для

размещения N объектов указанного размера, либо NULL, если

запрос не может быть удволетворен. Отводимая память инициа-

лизируется нулевыми значениями.

Указатель обладает нужным для рассматриваемых объектов

выравниванием, но ему следует приписывать соответствующий

тип, как в

CHAR *CALLOC();

INT *IP;

IP=(INT*) CALLOC(N,SIZEOF(INT));

Функция CFREE(P) освобождает пространство, на которое

указывает “P”, причем указатель “P” певоначально должен быть

получен в результате обращения к CALLOC. Здесь нет никаких

ограничений на порядок освобождения пространства, но будет

неприятнейшей ошибкой освободить что-нибудь, что не было по-

лучено обращением к CALLOC.

Реализация программы распределения памяти, подобной

CALLOC, в которой размещенные блоки могут освобождаться в

произвольном порядке, продемонстрирована в главе 8.

· 167 -

8. Интерфейс системы UNIX

Материал этой главы относится к интерфейсу между с-прог-

раммами и операционной системой UNIX. Так как большинство

пользователей языка “C” работают на системе UNIX, эта глава

окажется полезной для большинства читателей. даже если вы

используете с-компилятор на другой машине, изучение приводи-

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

тоды программирования на языке “C”.

Эта глава делится на три основные части: ввод/вывод,

система файлов и распределение памяти. Первые две части

предполагают небольшое знакомство с внешними характеристика-

ми системы UNIX.

В главе 7 мы имели дело с системным интерфейсом, который

одинаков для всего многообразия операционных систем. На каж-

дой конкретной системе функции стандартной библиотеки должны

быть написаны в терминах ввода-вывода, доступных на данной

машине. В следующих нескольких разделах мы опишем основную

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

ной системы UNIX и проиллюстрируем, как с их помощью могут

быть реализованы различные части стандартной библиотеки.

8.1. Дескрипторы файлов

В операционной системе UNIX весь ввод и вывод осуществ-

ляется посредством чтения файлов или их записи, потому что

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

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

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

зями между программой и периферийными устройствами.

В наиболее общем случае перед чтением из файла или за-

писью в файл необходимо сообщить системе о вашем намерении;