- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
STDIN_FILENO «Номер файла» для стандартного ввода: 0.
STDOUT_FILENO Номер файла для стандартного вывода: 1.
STDERR_FILENO Номер файла для стандартной ошибки: 2.
Однако, по нашему скромному мнению, использование этих макросов избыточно. Во-первых, неприятно набирать 12 или 13 символов вместо 1. Во-вторых, использование 0, 1 и 2 так стандартно и так хорошо известно, что на самом деле нет никаких оснований для путаницы в смысле этих конкретных символических констант.
С другой стороны, использование этих констант не оставляет сомнений в намерениях программиста. Сравните это утверждение:
int fd = 0;
Инициализируется ли fd значением стандартного ввода, или же программист благоразумно инициализирует свои переменные подходящим значением? Вы не можете этого сказать.
Один из подходов (рекомендованный Джеффом Колье (Geoff Collyer)) заключается в использовании следующего определения enum:
enum { Stdin, Stdout, Stderr };
Затем эти константы можно использовать вместо 0, 1 и 2. Их легко читать и печатать.
4.4.2. Открытие и закрытие файлов
Новые дескрипторы файлов получают (наряду с другими источниками) в результате системного вызова open(). Этот системный вызов открывает файл для чтения или записи и возвращает новый дескриптор файла для последующих операций с этим файлом. Мы видели объявление раньше:
#include <sys/types.h> /* POSIX */
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int open(const char *pathname, int flags, mode_t mode);
Три аргумента следующие:
const char *pathname
Строка С, представляющая имя открываемого файла.
int flags
Поразрядное ИЛИ с одной или более констант, определенных в <fcntl.h>. Вскоре мы их рассмотрим.
mode_t mode
Режимы доступа для создаваемого файла. Это обсуждается далее в главе, см. раздел 4.6 «Создание файлов». При открытии существующего файла опустите этот параметр[46].
Возвращаемое open() значение является либо новым дескриптором файла, либо -1, означающим ошибку, в этом случае будет установлена errno. Для простого ввода/вывода аргумент flags должен быть одним из значений из табл. 4.3.
Таблица 4.3. Значения flags для open()
Именованная константа Значение Комментарий O_RDONLY 0 Открыть файл только для чтения, запись невозможны O_WRONLY 1 Открыть файл только для записи, чтение невозможно O_RDWR 2 Открыть файл для чтения и записиВскоре мы увидим пример кода. Дополнительные значения flags описаны в разделе 4.6 «Создание файлов». Большой объем ранее написанного кода Unix не использовал эти символические значения. Вместо этого использовались числовые значения. Сегодня это рассматривается как плохая практика, но мы представляем эти значения, чтобы вы их распознали, если встретитесь с ними
Системный вызов close() закрывает файл: его элемент в системной таблице дескрипторов файлов помечается как неиспользуемый, и с этим дескриптором нельзя производить никаких дальнейших действий. Объявление следующее:
#include <unistd.h> /* POSIX */
int close(int fd);
В случае успеха возвращается 0, при ошибке (-1). При возникновении ошибки нельзя ничего сделать, кроме сообщения о ней. Ошибки при закрытии файлов являются необычными, но не невозможными, особенно для файлов, доступ к которым осуществляется через сеть. Поэтому хорошей практикой является проверка возвращаемого значения, особенно для файлов, открытых для записи.
Если вы будете игнорировать возвращаемое значение, специально приведите его к типу void, чтобы указать, что вам не нужен результат:
(void)close(fd); /* отказ от возвращаемого значения */
Легкомысленность этого совета в том, что слишком большое количество приведений к void имеют тенденцию загромождать код. Например, несмотря на принцип «всегда проверять возвращаемое значение», чрезвычайно редко можно увидеть код, проверяющий возвращаемое значение printf() или приводящий его к void. Как и со многими аспектами программирования на С, здесь также требуются опыт и рассудительность.
Как упоминалось, число открытых файлов, если оно большое, ограничивается, и вам всегда следует закрывать файлы, когда работа с ними закончена. Если вы этого не сделаете, то в конечном счете выйдете за пределы лимита дескрипторов файлов, создав ситуацию, которая ведет к потере устойчивости части вашей программы.
Система закрывает все открытые файлы, когда процесс завершается, но — за исключением 0, 1 и 2 — плохая манера полагаться на это.
Когда open() возвращает новый дескриптор файла, она всегда возвращает наименьшее неиспользуемое целое значение. Всегда. Поэтому, если открыты дескрипторы файлов 0–6 и программа закрывает дескриптор файла 5, следующий вызов open() вернет 5, а не 7. Это поведение важно; далее в книге мы увидим, как оно используется для аккуратной реализации многих важных особенностей Unix, таких, как перенаправление ввода/вывода и конвейеризация (piping)
4.4.2.1. Отображение переменных FILE* на дескрипторы файлов
Стандартные библиотечные функции ввода/вывода и переменные FILE* из <stdio.h>, такие, как stdin, stdout и stderr, построены поверх основанных на дескрипторах файлов системных вызовах.
Иногда полезно получить непосредственный доступ к дескриптору файла, связанному с указателем файла <stdio.h>, если вам нужно сделать что-либо, не определенное стандартом С ISO. Функция fileno() возвращает лежащий в основе дескриптор файла:
#include <stdio.h> /* POSIX */
int fileno(FILE *stream);
Пример мы увидим позже, в разделе 4.4.4. «Пример: Unix cat».
4.4.2.2. Закрытие всех открытых файлов
Открытые файлы наследуются порожденными процессами от своих родительских процессов. Фактически они являются общими. В частности, общим является положение в файле. Подробности мы оставим для дальнейшего обсуждения в разделе 9.1.1.2 «Разделение дескрипторов файлов».
Поскольку программы могут наследовать другие файлы, иногда вы можете увидеть программы, которые закрывают все свои файлы, чтобы начать с «чистого состояния» В частности, типичен код наподобие этого:
int i;
/* оставить лишь 0, 1, и 2 */
for (i = 3; i < getdtablesize(); i++)
(void)close(i);
Предположим, что результат getdtablesize() равен 1024. Этот код работает, но он делает (1024-3)*2 = 2042 системных вызова. 1020 из них не нужны, поскольку возвращаемое значение getdtablesize() не изменяется. Вот лучший вариант этого кода:
int i, fds;
for (i = 3, fds = getdtablesize(); i < fds; i++)
(void)close(i);
Такая оптимизация не ухудшает читаемость кода, но может быть заметна разница, особенно на медленных системах. В общем, стоит поискать случаи, когда в циклах повторно вычисляется один и тот же результат, чтобы посмотреть, нельзя ли вынести вычисление за пределы цикла. Хотя в таких случаях нужно убедиться, что вы (а) сохраняете правильность кода и (б) сохраняете его читаемость!
4.4.3. Чтение и запись
Ввод/вывод осуществляется системными вызовами read() и write() соответственно:
#include <sys/types.h> /* POSIX */
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
Каждая функция сделана как можно проще. Аргументами являются дескриптор открытого файла, указатель на буфер для чтения или записи данных и число читаемых или записываемых байтов.
Возвращаемое значение является числом действительно прочитанных или записанных байтов. (Это число может быть меньше запрошенного: при операции чтения это происходит, когда в файле осталось меньше count байтов, а при операции записи это случается, когда диск заполнен или произошла еще какая-нибудь ошибка.) Возвращаемое значение -1 означает возникшую ошибку, в этом случае errno указывает эту ошибку. Когда read() возвращает 0, это означает, что достигнут конец файла.

