KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Брайан Керниган - UNIX — универсальная среда программирования

Брайан Керниган - UNIX — универсальная среда программирования

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Брайан Керниган, "UNIX — универсальная среда программирования" бесплатно, без регистрации.
Перейти на страницу:

Таблица 6.1: Макросы классификации символов <ctype.h>


Вызов exit в конце vis не является необходимым для корректной работы программы, но гарантирует тому, кто эту программу вызвал, получение нормального кода ее завершения (обычно нуля). Другой способ возврата кода завершения выполнить в теле функции main оператор return 0; возвращаемое значение main и есть код завершения программы. Если нет явно указанных return или exit, код завершения не определен.

Для компиляции программы на Си поместите исходный текст в файл, имя которого оканчивается на .с, например vis.с, оттранслируйте его с помощью сс и запустите на выполнение результат, оставляемый компилятором в файле с именем a.out ('а' — ассемблер):

$ сс vis.с

$ a.out

hello worldctl^g

hello world07

ctl-d

$

a.out можно переименовать после первого запуска или сделать это сразу с помощью флага -о команды сс:

$ сс -о vis vis.с Результат в vis, а не в a.out

Упражнение 6.1

Мы решили, что символы табуляции не следует делать видимыми, изображая их как 11, → или t, поскольку главное назначение vis — поиск действительно аномальных символов. Можно принять альтернативное решение и недвусмысленно идентифицировать каждый символ в выходном потоке: символы табуляции, неграфические символы, пробелы в конце строки и т.п. Модифицируйте vis так, чтобы символы табуляции, обратная дробная черта, "шаг назад", перевод страницы и др. печатались в традиционном, принятом в Си представлении: t, \, b, f и т.д., причем пробелы в конце строки должны быть помечены. Можете сделать это недвусмысленным образом? Сравните ваш вариант с приведенным ниже:

$ sed -n 1

Упражнение 6.2

Модифицируйте vis так, чтобы она приводила длинные строки к строкам некоторой разумной длины. Как это согласуется с требованием недвусмысленности результата из предыдущего упражнения?

6.2 Аргументы программы: vis версия 2

Когда выполняется программа на Си, функции main передаются следующие аргументы из командной строки: счетчик argc и массив argv, состоящий из указателей символьных строк, содержащих аргументы. По соглашению argv[0] это имя самой команды, так что argc всегда больше нуля; "полезными" же являются аргументы argv[1]...argv[argc - 1]. Вспомните, что переключение входного или выходного потоков с помощью < и > осуществляется в shell, а не отдельными программами, поэтому такое переключение не влияет на число аргументов, видимых программой.

Для иллюстрации работы с аргументами модифицируем vis, добавив флаг: vis -s удаляет любые непечатаемые символы вместо того, чтобы выделять их. Такое удаление удобно для "чистки" файлов из других систем, например тех, которые используют для завершения строки CRLF (символы возврата каретки и перевода строки) вместо одного символа перевода строки.

/* vis: make funny characters visible (version 2) */


#include <stdio.h>

#include <ctype.h>


main(argc, argv)

 int argc;

 char *argv[];

{

 int c, strip = 0;


 if (argc > 1 && strcmp(argv[1], "-s") == 0)

  strip = 1;

 while ((c = getchar()) != EOF)

  if (isascii(c) &&

   (isprint(с) || c=='n' || c=='t' || c==' '))

   putchar(c);

  else if (!strip)

   printf("\%03o", c);

 exit(0);

}

Здесь argv — указатель массива, элементы которого служат указателями массивов символов; каждый такой массив заканчивается символом ASCII NUL (''), поэтому массив можно считать строкой. Эта версия vis начинает свою работу с того, что проверяет, есть ли аргумент и является ли он -s. (Неверные аргументы игнорируются.) Функция strcmp(3) сравнивает две строки, возвращая нуль, если они одинаковы.

В табл. 6.2 перечислены некоторые средства работы со строками и ряд полезных функций, одна из которых strcmp. Как правило, лучше воспользоваться этими стандартными функциями, чем писать собственные, так как они отлажены и зачастую выполняются быстрее, чем написанные вами, поскольку были оптимизированы для конкретных машин (нередко благодаря использованию Ассемблера).

strcat(s,t) Добавляет строку t к строке s; возвращает s strncat(s,t,n) Добавляет не более n символов t к s strcpy(s,t) Копирует t в s; возвращает s strncpy(s,t,n) Копирует точно n символов; при необходимости добавляет NULL strcmp(s,t) Сравнивает s и t, возвращает <0, 0, >0 при <, ==, > strncmp(s,t,n) Сравнивает не более n символов strlen(s) Возвращает длину s strchr(s,c) Возвращает указатель на первый символ с в s и NULL, если с отсутствует strrchr(s,c) Возвращает указатель на последний с в s и NULL, если с отсутствует. atoi(s) Возвращает целое значение s atof(s) Возвращает "плавающее" значение s; необходимо описание double atof() malloc(n) Возвращает указатель на область памяти в n байт и NULL, если это невозможно calloc(n,m) Возвращает указатель на n*m обнуленных байтов и NULL, если это невозможно; malloc и calloc возвращают значение типа char* free(p) Освобождает память, выделенную malloc и calloc

Таблица 6.2: Стандартные функции, выполняемые над строками


Упражнение 6.3

Измените аргумент -s так, чтобы vis -sn печатала только строки из n или более печатаемых символов, опуская непечатаемые символы и короткие последовательности обычных, печатаемых символов. Это полезно при выделении ''текстовых'' частей в нетекстовых файлах, таких, как рабочие программы. Некоторые версии системы содержат для подобных целей программу strings. Что лучше: иметь отдельную программу или пользоваться специальным аргументом vis?

Упражнение 6.4

Доступность исходной программы на Си — одно из достоинств системы UNIX; такая программа демонстрирует элегантные решения многих программистских проблем. Прокомментируйте баланс между наглядностью программы на Си и встречающимися "оптимизированными" фрагментами, переписанными на Ассемблере.

6.3 Доступ к файлам: vis версия 3

Две первые версии vis читают из стандартного входного потока и пишут в стандартный выходной поток, причем оба потока наследуются от shell. Следующий шаг модификация vis для работы с файлами по их именам, так что

$ vis файл1 файл2 ...

будет просматривать эти именованные файлы вместо стандартного входного потока. Если же имен файлов в качестве аргументов нет, vis должна читать стандартный входной поток.

Возникает вопрос: как организовать чтение файлов, т.е. как связать имена файлов с операторами ввода вывода, реально читающими данные? Правила просты. Прежде чем быть прочитанным или записанным, файл должен быть открыт стандартной библиотечной функцией fopen. Последняя берет имя файла (например, temp или /etc/passwd), взаимодействует с ядром и возвращает обратно "внутреннее имя", которое используется при последующих операциях с данным файлом.

Внутреннее имя является на самом деле указателем (называемым указателем файла) на структуру, содержащую информацию о файле, такую, как расположение буфера, текущую позицию символа в буфере, режим чтения или записи и т.п. Эта структура определяется в файле <stdio.h> и имеет имя FILE. Описание указателя файла таково:

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*