- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
#define getnode(n) if (nextfree) n = nextfree,
nextfree = nextfree->nextp; else n = more_nodes()
#define freenode(n) ((n)->flags = 0, (n)->exec_count = 0,
(n)->nextp = nextfree, nextfree = (n))
Переменная nextfree указывает на связанный список структур NODE. Макрос getnode() убирает из списка первую структуру, если она там есть. В противном случае она вызывает more_nodes(), чтобы выделить новый список свободных структур NODE. Макрос freenode() освобождает структуру NODE, помещая его в начало списка.
ЗАМЕЧАНИЕ. Первоначально при написании своего приложения делайте это простым способом: непосредственно используйте malloc() и free(). Написание собственного распределителя вы должны рассмотреть лишь в том и только в том случае, если профилирование вашей программы покажет, что она значительную часть времени проводит в функциях выделения памяти.
3.2.1.8. Пример: чтение строк произвольной длины
Поскольку это, в конце концов, Программирование на Linux в примерах, настало время для примера из реальной жизни. Следующий код является функцией readline() из GNU Make 3.80 (ftp://ftp.gnu.org/gnu/make/make-3.80.tar.gz). Ее можно найти в файле read.c.
Следуя принципу «никаких произвольных ограничений», строки в Makefile могут быть любой длины. Поэтому главной задачей этой процедуры является чтение строк произвольной длины и гарантирование того, что они помещаются в используемый буфер.
Вторичной задачей является распоряжение продлением строк. Как и в С, строки, заканчивающиеся обратным слешем, логически продолжаются со следующей строки. Используется стратегия поддержания буфера. В нем хранится столько строк, сколько помещается в буфер, причем указатели отслеживают начало буфера, текущую строку и следующую строку. Вот структура:
struct ebuffer {
char *buffer; /* Начало текущей строки в буфере. */
char *bufnext; /* Начало следующей строки в буфере. */
char *bufstart; /* Начало всего буфера. */
unsigned int size; /* Размер буфера для malloc. */
FILE *fp; /* Файл или NULL, если это внутренний буфер. */
struct floc floc; /* Информация о файле в fp (если он есть). */
};
Поле size отслеживает размер всего буфера, a fp является указателем типа FILE для файла ввода. Структура floc не представляет интереса при изучении процедуры.
Функция возвращает число строк в буфере. (Номера строк здесь даны относительно начала функции, а не исходного файла.)
1 static long
2 readline(ebuf) /* static long readline(struct ebuffer *ebuf) */
3 struct ebuffer *ebuf;
4 {
5 char *p;
6 char *end;
7 char *start;
8 long nlines = 0;
9
10 /* Использование строковых буферов и буферов потоков достаточно
11 различается, чтобы использовать разные функции. */
12
13 if (!ebuf->fp)
14 return readstring(ebuf);
15
16 /* При чтении из файла для каждой новой строки мы всегда
17 начинаем с начала буфера. */
18
19 p = start = ebuf->bufstart;
20 end = p + ebuf->size;
21 *p = ' ';
Для начала заметим, что GNU Make написан на С K&R для максимальной переносимости. В исходной части объявляются переменные, и если ввод осуществляется из строки (как в случае расширения макроса), код вызывает другую функцию, readstring() (строки 13 и 14). Строка '!ebuf->fp' (строка 13) является более короткой (и менее понятной, по нашему мнению) проверкой на пустой указатель; это то же самое, что и 'ebuf->fp==NULL'.
Строки 19-21 инициализируют указатели и вводят байт NUL, который является символом завершения строки С в конце буфера. Затем функция входит в цикл (строки 23–95), который продолжается до завершения всего ввода.
23 while (fgets(p, end - р, ebuf->fp) != 0)
24 {
25 char *p2;
26 unsigned long len;
27 int backslash;
28
29 len = strlen(p);
30 if (len == 0)
31 {
32 /* Это случается лишь тогда, когда первый символ строки ' '.
33 Это довольно безнадежный случай, но (верите или нет) ляп Афины
34 бьет снова! (xmkmf помещает NUL в свои makefile.)
35 Здесь на самом деле нечего делать; мы создаем новую строку, чтобы
36 следующая строка не была частью данной строки. */
37 error (&ebuf->floc,
38 _("warning: NUL character seen; rest of line ignored"));
39 p[0] = 'n';
40 len = l;
41 }
Функция fgets() (строка 23) принимает указатель на буфер, количество байтов для прочтения и переменную FILE* для файла, из которого осуществляется чтение. Она читает на один байт меньше указанного, чтобы можно было завершить буфер символом ' '. Эта функция подходит, поскольку она позволяет избежать переполнения буфера. Она прекращает чтение, когда встречается с символами конца строки или конца файла; если это символ новой строки, он помещается в буфер. Функция возвращает NULL при неудаче или значение указателя первого аргумента при успешном завершении.
В этом случае аргументами являются указатель на свободную область буфера, размер оставшейся части буфера и указатель FILE для чтения.
Комментарии в строках 32–36 очевидны; если встречается нулевой байт, программа выводит сообщение об ошибке и представляет вывод как пустую строку. После компенсирования нулевого байта (строки 30–41) код продолжает работу.
43 /* Обойти только что прочитанный текст. */
44 p += len;
45
46 /* Если последний символ - не конец строки, она не поместилась
47 целиком в буфер. Увеличить буфер и попытаться снова. */
48 if (p[-1] != 'n')
49 goto more_buffer;
50
51 /* Мы получили новую строку, увеличить число строк. */
52 ++nlines;
Строки 43–52 увеличивают указатель на участок буфера за только что прочитанными данными. Затем код проверяет, является ли последний прочитанный символ символом конца строки. Конструкция p[-1] (строка 48) проверяет символ перед p, также как p[0] является текущим символом, а p[1] — следующим. Сначала это кажется странным, но если вы переведете это на язык математики указателей, *(p-1), это приобретет больший смысл, а индексированная форма, возможно, проще для чтения.
Если последний символ не был символом конца строки, это означает, что нам не хватило места, и код выходит (с помощью goto) для увеличения размера буфера (строка 49). В противном случае увеличивается число строк.
54 #if !defined(WINDOWS32) && !defined(__MSDOS__)
55 /* Проверить, что строка завершилась CRLF; если так,
56 игнорировать CR. */
57 if ((p - start) > 1 && p[-2] == 'r')
58 {
59 --p;
60 p[-1] = 'n';
61 }
62 #endif
Строки 54–62 обрабатывают вводимые строки, следующие соглашению Microsoft по завершению строк комбинацией символов возврата каретки и перевода строки (CR-LF), а не просто символом перевода строки (новой строки), который является соглашением Linux/Unix. Обратите внимание, что #ifdef исключает этот код на платформе Microsoft, очевидно, библиотека <stdio.h> на этих системах автоматически осуществляет это преобразование. Это верно также для других не-Unix систем, поддерживающих стандартный С.
64 backslash = 0;
65 for (p2 = p - 2; p2 >= start; --p2)
66 {
67 if (*p2 != '\')
68 break;
69 backslash = !backslash;
70 }
71
72 if (!backslash)
73 {
74 p[-1] = ' ';
75 break;
76 }
77
78 /* Это была комбинация обратный слеш/новая строка. Если есть
79 место, прочесть еще одну строку. */
80 if (end - p >= 80)
81 continue;
82
83 /* В конце буфера нужно больше места, поэтому выделить еще.
84 Позаботиться о сохранении текущего смещения в p. */
85 more_buffer:
86 {
87 unsigned long off = p - start;
88 ebuf->size *= 2;
89 start = ebuf->buffer=ebuf->bufstart=(char*)xrealloc(start,
90 ebuf->size);
91 p = start + off;
92 end = start + ebuf->size;
93 *p = ' ';
94 }
95 }
До сих пор мы имели дело с механизмом получения в буфер по крайней мере одной полной строки. Следующий участок обрабатывает случай строки с продолжением. Хотя он должен гарантировать, что конечный символ обратного слеша не является частью нескольких обратных слешей в конце строки. Код проверяет, является ли общее число таких символов четным или нечетным путем простого переключения переменной backslash из 0 в 1 и обратно. (Строки 64–70.)

