Страница 76 из 187
Таблица 6.1: Макросы классификации символов <ctype.h>
Вызов exit в конце vis не является необходимым для корректной работы программы, но гарантирует тому, кто эту программу вызвал, получение нормального кода ее завершения (обычно нуля). Другой способ возврата кода завершения выполнить в теле функции main оператор return 0; возвращаемое значение main и есть код завершения программы. Если нет явно указанных return или exit, код завершения не определен.
Для компиляции программы на Си поместите исходный текст в файл, имя которого оканчивается на .с, например vis.с, оттранслируйте его с помощью сс и запустите на выполнение результат, оставляемый компилятором в файле с именем a.out ('а' — ассемблер):
$ сс vis.с
$ a.out
hello worldctl^g
hello world 07
ctl-d
$
a.out можно переименовать после первого запуска или сделать это сразу с помощью флага -о команды сс:
$ сс -о vis vis.с Результат в vis, а не в a.out
Мы решили, что символы табуляции не следует делать видимыми, изображая их как 11, → или t, поскольку главное назначение vis — поиск действительно аномальных символов. Можно принять альтернативное решение и недвусмысленно идентифицировать каждый символ в выходном потоке: символы табуляции, неграфические символы, пробелы в конце строки и т.п. Модифицируйте vis так, чтобы символы табуляции, обратная дробная черта, "шаг назад", перевод страницы и др. печатались в традиционном, принятом в Си представлении: t, \, b, f и т.д., причем пробелы в конце строки должны быть помечены. Можете сделать это недвусмысленным образом? Сравните ваш вариант с приведенным ниже:
$ sed -n 1
Модифицируйте vis так, чтобы она приводила длинные строки к строкам некоторой разумной длины. Как это согласуется с требованием недвусмысленности результата из предыдущего упражнения?
6.2 Аргументы программы: vis версия 2
Когда выполняется программа на Си, функции main передаются следующие аргументы из командной строки: счетчик argc и массив argv, состоящий из указателей символьных строк, содержащих аргументы. По соглашению argv[0] это имя самой команды, так что argc всегда больше нуля; "полезными" же являются аргументы argv[1]...argv[argc - 1]. Вспомните, что переключение входного или выходного потоков с помощью < и > осуществляется в shell, а не отдельными программами, поэтому такое переключение не влияет на число аргументов, видимых программой.
Для иллюстрации работы с аргументами модифицируем vis, добавив флаг: vis -s удаляет любые непечатаемые символы вместо того, чтобы выделять их. Такое удаление удобно для "чистки" файлов из других систем, например тех, которые используют для завершения строки CRLF (символы возврата каретки и перевода строки) вместо одного символа перевода строки.
/* vis: make fu
#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. Как правило, лучше воспользоваться этими стандартными функциями, чем писать собственные, так как они отлажены и зачастую выполняются быстрее, чем написанные вами, поскольку были оптимизированы для конкретных машин (нередко благодаря использованию Ассемблера).