Linux программирование в примерах | страница 61



Например, GNU awk (gawk) использует эту методику. Выдержка из файла >awk.h в дистрибутиве >gawk (слегка отредактировано, чтобы уместилось на странице):

>#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 не представляет интереса при изучении процедуры.