Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное
- Название:Язык программирования Си. Издание 3-е, исправленное
- Автор:
- Жанр:
- Издательство:Невский Диалект
- Год:2001
- Город:Санкт-Петербург
- ISBN:0-13-110362-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное краткое содержание
Книга широко известных авторов, разработчиков языка Си, переработанная и дополненная с учетом стандарта ANSI для языка Си, 2-е английское издание которой вышло в 1988 году, давно стала классикой для всех изучающих и/или использующих как Си, так и Си++. Русский перевод этой книги впервые был выпущен изд- вом "Финансы и статистика" в 1992 г. и с тех пор пользуется неизменным спросом читателей.
Для настоящего третьего русского издания перевод заново сверен с оригиналом, в него внесены некоторые поправки, учитывающие устоявшиеся за прошедшие годы изменения в терминологии, а так же учтены замечания, размещенные автором на странице http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html.
Для программистов, преподавателей и студентов.
Издание подготовлено при участии издательства "Финансы и статистика"
Язык программирования Си. Издание 3-е, исправленное - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
FILE _iob[OPEN_MAX] = { /* stdin, stdout, stderr: */
{ 0, (char *) 0, (char *) 0, _READ, 0 },
{ 0, (char *) 0, (char *) 0, _WRITE, 1 },
{ 0, (char *) 0, (char *) 0, _WRITE | _UNBUF, 2 }
};
Инициализация flag как части структуры показывает, что stdin открыт на чтение, stdout - на запись, а stderr - на запись без буферизации.
Упражнение 8.2. Перепишите функции fopen и _fillbuf , работая с флажками как с полями, а не с помощью явных побитовых операций. Сравните размеры и скорости двух вариантов программ.
Упражнение 8.3. Разработайте и напишите функции _flushbuf , fflush и fclose .
Упражнение 8.4. Функция стандартной библиотеки
int fseek(FILE *fp, long offset, int origin)
идентична функции lseek с теми, однако, отличиями, что fp - это файловый указатель, а не дескриптор, и возвращает она значение int , означающее состояние файла, а не позицию в нем. Напишите свою версию fseek . Обеспечьте, чтобы работа вашей fseek по буферизации была согласована с буферизацией, используемой другими функциями библиотеки.
8.6 Пример. Печать каталогов
При разного рода взаимодействиях с файловой системой иногда требуется получить только информацию о файле, а не его содержимое. Такая потребность возникает, например, в программе печати каталога файлов, работающей аналогично команде ls системы UNIX. Она печатает имена файлов каталога и по желанию пользователя другую дополнительную информацию (размеры, права доступа и т. д.). Аналогичной командой в MS-DOS является dir .
Так как в системе UNIX каталог - это тоже файл, функции ls , чтобы добраться до имен файлов, нужно только его прочитать. Но чтобы получить другую информацию о файле (например узнать его размер), необходимо выполнить системный вызов. В других системах (в MS-DOS, например) системным вызовом приходится пользоваться даже для получения доступа к именам файлов. Наша цель - обеспечить доступ к информации по возможности системно-независимым способом несмотря на то, что реализация может быть существенно системно-зависима. Проиллюстрируем сказанное написанием программы fsize . Функция fsize - частный случай программы ls : она печатает размеры всех файлов, перечисленных в командной строке. Если какой-либо из файлов сам является каталогом, то, чтобы получить информацию о нем, fsize обращается сама к себе. Если аргументов в командной строке нет, то обрабатывается текущий каталог.
Для начала вспомним структуру файловой системы в UNIXe. Каталог - это файл, содержащий список имен файлов и некоторую информацию о том, где они расположены. "Место расположения" - это индекс, обеспечивающий доступ в другую таблицу, называемую "списком узлов inode". Для каждого файла имеется свой inode , где собрана вся информация о файле, за исключением его имени. Каждый элемент каталога состоит из двух частей: из имени файла и номера узла inode .
К сожалению, формат и точное содержимое каталога не одинаковы в разных версиях системы. Поэтому, чтобы переносимую компоненту отделить от непереносимой, разобьем нашу задачу на две. Внешний уровень определяет структуру, названную Dirent , и три подпрограммы opendir , readdir и closedir : в результате обеспечивается системно-независимый доступ к имени и номеру узла inode каждого элемента каталога. Мы будем писать программу fsize , рассчитывая на такой интерфейс, а затем покажем, как реализовать указанные функции для систем, использующих ту же структуру каталога, что и Version 7 и System V UNIX. Другие варианты оставим для упражнений.
Структура Dirent содержит номер узла inode и имя. Максимальная длина имени файла равна NAME_MAX - это значение системно-зависимо. Функция opendir возвращает указатель на структуру, названную DIR (по аналогии с FILE ), которая используется функциями readdir и closedir . Эта информация сосредоточена в заголовочном файле dirent.h .
#define NAME_MAX 14 /* максимальная длина имени файла */
/* системно-зависимая величина */
typedef struct { /* универс. структура элемента каталога: */
long ino; /* номер inode */
char name[NAME_MAX+1]; /* имя + завершающий '\0' */
} Dirent;
typedef struct { /* минимальный DIR: без буферизации и т.д. */
int fd; /* файловый дескриптор каталога */
Dirent d; /* элемент каталога */
} DIR;
DIR *opendir(char *dirname);
Dirent *readdir(DIR *dfd);
void closedir(DIR *dfd);
Системный вызов stat получает имя файла и возвращает полную о нем информацию, содержащуюся в узле inode , или -1 в случае ошибки. Так,
char *name;
struct stat stbuf;
int stat(char *, struct stat *);
stat(name, &stbuf);
заполняет структуру stbuf информацией из узла inode о файле с именем name . Структура, описывающая возвращаемое функцией stat значение находится в ‹sys/stat.h› и выглядит примерно так:
struct stat /* информация из inode, возвращаемая stat */
{
dev_t st_dev; /* устройство */
ino_t st_ino; /* номер inode */
short st_mode; /* режимные биты */
short st_nlink; /* число связей с файлом */
short st_uid; /* имя пользователя-собственника */
short st_gid; /* имя группы собственника */
dev_t st_rdev; /* для специальных файлов */
off_t st_size; /* размер файла в символах */
time_t st_atime; /* время последнего использования */
time_t st_mtime; /* время последней модификации */
time_t st_ctime; /* время последнего изменения inode */
};
Большинство этих значений объясняется в комментариях. Типы, подобные dev_t и ino_t , определены в файле ‹sys/types.h›, который тоже нужно включить посредством #include .
Элемент st_mode содержит набор флажков, составляющих дополнительную информацию о файле. Определения флажков также содержатся в ‹sys/stat.h› нам потребуется только та его часть, которая имеет дело с типом файла
#define S_IFMT 0160000 /* тип файла */
#define S_IFDIR 0040000 /* каталог */
#define S_IFCHR 0020000 /* символьно-ориентированный */
#define S_IFBLK 0060000 /* блочно-ориентированный */
#define S_IFREG 0100000 /* обычный */
Теперь мы готовы приступить к написанию программы fsize . Если режимные биты ( st_mode ), полученные от stat , указывают, что файл не является каталогом, то можно взять его размер ( st_size ) и напечатать. Однако если файл - каталог, то мы должны обработать все его файлы, каждый из которых в свою очередь может быть каталогом. Обработка каталога - процесс рекурсивный.
Программа main просматривает параметры командной строки, передавая каждый аргумент функции fsize .
#include ‹stdio.h›
#include ‹string.h›
#include "syscalls.h"
#include ‹fcntl.h› /* флажки чтения и записи */
#include ‹sys/types.h› /* определения типов */
Интервал:
Закладка: