QUEUE(3)

ИМЯ
SLIST_EMPTY, SLIST_ENTRY, SLIST_FIRST, SLIST_FOREACH, SLIST_HEAD, SLIST_HEAD_INITIALIZER, SLIST_INIT, SLIST_INSERT_AFTER, SLIST_INSERT_HEAD, SLIST_NEXT, SLIST_REMOVE_HEAD, SLIST_REMOVE, STAILQ_CONCAT, STAILQ_EMPTY, STAILQ_ENTRY, STAILQ_FIRST, STAILQ_FOREACH, STAILQ_HEAD, STAILQ_HEAD_INITIALIZER, STAILQ_INIT, STAILQ_INSERT_AFTER, STAILQ_INSERT_HEAD, STAILQ_INSERT_TAIL, STAILQ_NEXT, STAILQ_REMOVE_HEAD, STAILQ_REMOVE, LIST_EMPTY, LIST_ENTRY, LIST_FIRST, LIST_FOREACH, LIST_HEAD, LIST_HEAD_INITIALIZER, LIST_INIT, LIST_INSERT_AFTER, LIST_INSERT_BEFORE, LIST_INSERT_HEAD, LIST_NEXT, LIST_REMOVE, TAILQ_CONCAT, TAILQ_EMPTY, TAILQ_ENTRY, TAILQ_FIRST, TAILQ_FOREACH, TAILQ_FOREACH_REVERSE, TAILQ_HEAD, TAILQ_HEAD_INITIALIZER, TAILQ_INIT, TAILQ_INSERT_AFTER, TAILQ_INSERT_BEFORE, TAILQ_INSERT_HEAD, TAILQ_INSERT_TAIL, TAILQ_LAST, TAILQ_NEXT, TAILQ_PREV, TAILQ_REMOVE, TAILQ_SWAP - реализации односвязных списков, односвязных хвостовых очередей, списков и хвостовых очередей

ОБЗОР
<sys/queue.h> SLIST_EMPTY(SLIST_HEAD *head) SLIST_ENTRY(TYPE) SLIST_FIRST(SLIST_HEAD *head) SLIST_FOREACH(TYPE *var, SLIST_HEAD *head, SLIST_ENTRY NAME) SLIST_HEAD(HEADNAME, TYPE) SLIST_HEAD_INITIALIZER(SLIST_HEAD head) SLIST_INIT(SLIST_HEAD *head) SLIST_INSERT_AFTER(TYPE *listelm, TYPE *elm, SLIST_ENTRY NAME) SLIST_INSERT_HEAD(SLIST_HEAD *head, TYPE *elm, SLIST_ENTRY NAME) SLIST_NEXT(TYPE *elm, SLIST_ENTRY NAME) SLIST_REMOVE_HEAD(SLIST_HEAD *head, SLIST_ENTRY NAME) SLIST_REMOVE(SLIST_HEAD *head, TYPE *elm, TYPE, SLIST_ENTRY NAME) STAILQ_CONCAT(STAILQ_HEAD *head1, STAILQ_HEAD *head2) STAILQ_EMPTY(STAILQ_HEAD *head) STAILQ_ENTRY(TYPE) STAILQ_FIRST(STAILQ_HEAD *head) STAILQ_FOREACH(TYPE *var, STAILQ_HEAD *head, STAILQ_ENTRY NAME) STAILQ_HEAD(HEADNAME, TYPE) STAILQ_HEAD_INITIALIZER(STAILQ_HEAD head) STAILQ_INIT(STAILQ_HEAD *head) STAILQ_INSERT_AFTER(STAILQ_HEAD *head, TYPE *listelm, TYPE *elm, STAILQ_ENTRY NAME) STAILQ_INSERT_HEAD(STAILQ_HEAD *head, TYPE *elm, STAILQ_ENTRY NAME) STAILQ_INSERT_TAIL(STAILQ_HEAD *head, TYPE *elm, STAILQ_ENTRY NAME) STAILQ_NEXT(TYPE *elm, STAILQ_ENTRY NAME) STAILQ_REMOVE_HEAD(STAILQ_HEAD *head, STAILQ_ENTRY NAME) STAILQ_REMOVE(STAILQ_HEAD *head, TYPE *elm, TYPE, STAILQ_ENTRY NAME) LIST_EMPTY(LIST_HEAD *head) LIST_ENTRY(TYPE) LIST_FIRST(LIST_HEAD *head) LIST_FOREACH(TYPE *var, LIST_HEAD *head, LIST_ENTRY NAME) LIST_HEAD(HEADNAME, TYPE) LIST_HEAD_INITIALIZER(LIST_HEAD head) LIST_INIT(LIST_HEAD *head) LIST_INSERT_AFTER(TYPE *listelm, TYPE *elm, LIST_ENTRY NAME) LIST_INSERT_BEFORE(TYPE *listelm, TYPE *elm, LIST_ENTRY NAME) LIST_INSERT_HEAD(LIST_HEAD *head, TYPE *elm, LIST_ENTRY NAME) LIST_NEXT(TYPE *elm, LIST_ENTRY NAME) LIST_REMOVE(TYPE *elm, LIST_ENTRY NAME) LIST_SWAP(LIST_HEAD *head1, LIST_HEAD *head2, TYPE, LIST_ENTRY NAME) TAILQ_CONCAT(TAILQ_HEAD *head1, TAILQ_HEAD *head2, TAILQ_ENTRY NAME) TAILQ_EMPTY(TAILQ_HEAD *head) TAILQ_ENTRY(TYPE) TAILQ_FIRST(TAILQ_HEAD *head) TAILQ_FOREACH(TYPE *var, TAILQ_HEAD *head, TAILQ_ENTRY NAME) TAILQ_FOREACH_REVERSE(TYPE *var, TAILQ_HEAD *head, HEADNAME, TAILQ_ENTRY NAME) TAILQ_HEAD(HEADNAME, TYPE) TAILQ_HEAD_INITIALIZER(TAILQ_HEAD head) TAILQ_INIT(TAILQ_HEAD *head) TAILQ_INSERT_AFTER(TAILQ_HEAD *head, TYPE *listelm, TYPE *elm, TAILQ_ENTRY NAME) TAILQ_INSERT_BEFORE(TYPE *listelm, TYPE *elm, TAILQ_ENTRY NAME) TAILQ_INSERT_HEAD(TAILQ_HEAD *head, TYPE *elm, TAILQ_ENTRY NAME) TAILQ_INSERT_TAIL(TAILQ_HEAD *head, TYPE *elm, TAILQ_ENTRY NAME) TAILQ_LAST(TAILQ_HEAD *head, HEADNAME) TAILQ_NEXT(TYPE *elm, TAILQ_ENTRY NAME) TAILQ_PREV(TYPE *elm, HEADNAME, TAILQ_ENTRY NAME) TAILQ_REMOVE(TAILQ_HEAD *head, TYPE *elm, TAILQ_ENTRY NAME) TAILQ_SWAP(TAILQ_HEAD *head1, TAILQ_HEAD *head2, TYPE, TAILQ_ENTRY NAME)

ОПИСАНИЕ
Данные макросы определяют и управляют четырьмя типами структур данных: односвязными списками, односвязными хвостовыми очередями, списками и хвостовыми очередями. Все четыре структуры поддерживают следующие возможности:
1.  Вставка нового элемента в начало списка.
2.  Вставка нового элемента после любого элемента списка.
3.  Удаление элемента из начала списка за время O(1).
4.  Обход списка из начала в конец.
5.  Перестановка содержимого двух списков.

Односвязные списки — самая простая из этих четырёх структур данных и поддерживает только указанные выше возможности. Односвязные списки идеальны для приложений с большими наборами данных, из которых производится очень мало удалений, или для реализации очереди LIFO (последним пришёл — первым ушёл). У односвязных списков есть дополнительное свойство:
1.  Удаление любого элемента списка за время O(n).

У односвязных хвостовых очередей есть дополнительные свойства:
1.  Добавление элементов в конец списка.
2.  Удаление любого элемента списка за время O(n).
3.  Возможность объединения.
Однако:
1.  При вставке элементов нужно указывать начало списка.
2.  Каждый начальный элемент требует двух указателей вместо одного.
3.  Код примерно на 15% больше и на 20% медленнее, чем для односвязных списков.

Односвязные хвостовые очереди идеальны для приложений с большими наборами данных из которых производится очень мало удалений, или для реализации очереди FIFO (первым пришёл — первым ушёл).

Все двусвязные типы структур данных (списки и хвостовые очереди) дополнительно позволяют:
1.  Вставку нового элемента перед любым элементом списка.
2.  Удаление любого элемента списка за время O(1).
Однако:
1.  Для каждого элемента требуется два указателя вместо одного.
2.  Размер кода и время выполнения операций (кроме удаления) удваивается, по сравнению с односвязными структурами данных.

Связные списки — самая простая из двусвязных структур данных. К указанным выше возможностям для них возможно:
1.  Обход в обратном направлении.
Однако:
1.  Для обхода в обратном направлении требуется указывать начало обхода и сам список.

У хвостовых очередей есть дополнительные свойства:
1.  Добавление элементов в конец списка.
2.  Обход может идти в обратном направлении, от конца к началу.
3.  Возможность объединения.
Однако:
1.  При вставке и удалении элементов нужно указывать начало списка.
2.  Каждый начальный элемент требует двух указателей вместо одного.
3.  Код примерно на 15% больше и на 20% медленнее, чем для односвязных списков.

В определениях макросов TYPE — это имя определяемое пользователем структуры, которая должна содержать поле типа SLIST_ENTRY, STAILQ_ENTRY, LIST_ENTRY или TAILQ_ENTRY, названное NAME. Аргумент HEADNAME — это имя определяемое пользователем структуры, которая должна быть объявлена с помощью макроса SLIST_HEAD, STAILQ_HEAD, LIST_HEAD или TAILQ_HEAD. Ниже показаны примеры использования этих макросов.

  Односвязные списки
Односвязный список начинается со структуры, определённой макросом SLIST_HEAD. В этой структуре содержится одиночный указатель на первый элемент списка. Элементы имеют по одной связи для минимизации занимаемого пространства, а дополнительный расход на операции с указателями равен O(n) при удалении произвольного элемента. Новые элементы можно добавлять в список после существующего элемента или в начало списка. Структура SLIST_HEAD объявляется следующим образом:

    SLIST_HEAD(HEADNAME, TYPE) head;

где HEADNAME — имя определяемой структуры, а TYPE — тип элементов, объединяемых в список. Указатель на начало списка может в дальнейшем объявляться так:

    struct HEADNAME *headp;

(Имена head и headp могут выбираться пользователем.)

Макрос SLIST_HEAD_INITIALIZER запускает инициализатор для head списка.

Макрос SLIST_EMPTY возвращает true, если в списке нет элементов.

Макрос SLIST_ENTRY объявляет структуру, которая добавляет элементы в список.

Макрос SLIST_FIRST возвращает первый элемент списка или NULL, если список пуст.

Макрос SLIST_FOREACH обходит список, на который ссылается head, от начало в конец, назначая var каждый элемент.

Макрос SLIST_INIT инициализирует список, на который ссылается head.

Макрос SLIST_INSERT_HEAD вставляет новый элемент elm в начало списка.

Макрос SLIST_INSERT_AFTER вставляет новый элемент elm за элементом listelm.

Макрос SLIST_NEXT возвращает следующий элемент списка.

Макрос SLIST_REMOVE_HEAD удаляет элемент elm из начала списка. В целях эффективности удаления элемента из начала списка нужно использовать именно этот макрос вместо обычного SLIST_REMOVE.

Макрос SLIST_REMOVE удаляет элемент elm из списка.

  Пример односвязного списка

    SLIST_HEAD(slisthead, entry) head =
        SLIST_HEAD_INITIALIZER(head);
    struct slisthead *headp;		/* начало односвязного списка */
    struct entry {
    	...
    	SLIST_ENTRY(entry) entries;	/* односвязный список */
    	...
    } *n1, *n2, *n3, *np;
    SLIST_INIT(&head);			/* инициализация списка */
    n1 = malloc(sizeof(struct entry));	/* вставка начального элемента */
    SLIST_INSERT_HEAD(&head, n1, entries);
    n2 = malloc(sizeof(struct entry));	/* вставка последующих */
    SLIST_INSERT_AFTER(n1, n2, entries);
    SLIST_REMOVE(&head, n2, entry, entries);/* удаление */
    free(n2);
    n3 = SLIST_FIRST(&head);
    SLIST_REMOVE_HEAD(&head, entries);	/* удаление начального элемента */
    free(n3);
    					/* обход из начала в конец */
    SLIST_FOREACH(np, &head, entries)
    	np-> ...
    while (!SLIST_EMPTY(&head)) {		/* удаление списка */
    	n1 = SLIST_FIRST(&head);
    	SLIST_REMOVE_HEAD(&head, entries);
    	free(n1);
    }

  Односвязные хвостовые очереди
Односвязная хвостовая очередь начинается со структуры, определяемой макросом STAILQ_HEAD. В этой структуре содержится пара указателей, один на первый элемент хвостовой очереди, а другой на последний элемент. Элементы имеют по одной связи для минимизации занимаемого пространства, а дополнительный расход на операции с указателями равен O(n) при удалении произвольного элемента. Новые элементы можно добавлять в хвостовую очередь после существующего элемента, в начало или конец хвостовой очереди, Структура STAILQ_HEAD объявляется следующим образом:

    STAILQ_HEAD(HEADNAME, TYPE) head;

где HEADNAME — имя определяемой структуры, а TYPE — тип связанных элементов в хвостовой очереди. Указатель на начало хвостовой очереди может в дальнейшем объявляться так:

    struct HEADNAME *headp;

(Имена head и headp могут выбираться пользователем.)

Макрос STAILQ_HEAD_INITIALIZER запускает инициализатор для head хвостовой очереди.

Макрос STAILQ_CONCAT добавляет хвостовую очередь с началом head2 в конец очереди с началом head1, удаляя все элементы из первой.

Макрос STAILQ_EMPTY возвращает true, если в хвостовой очереди нет элементов.

Макрос STAILQ_ENTRY объявляет структуру, которая подключает элементы в хвостовую очередь.

Макрос STAILQ_FIRST возвращает первый элемент из хвостовой очереди или NULL, если очередь пуста.

Макрос STAILQ_FOREACH обходит хвостовую очередь, на которую ссылается head, из начала в конец, назначая var каждый элемент.

Макрос STAILQ_INIT инициализирует хвостовую очередь, на которую ссылается head.

Макрос STAILQ_INSERT_HEAD вставляет новый элемент I elm в начало хвостовой очереди.

Макрос STAILQ_INSERT_TAIL вставляет новый элемент elm в конец хвостовой очереди.

Макрос STAILQ_INSERT_AFTER вставляет новый элемент elm за элементом listelm.

Макрос STAILQ_NEXT возвращает следующий элемент из хвостовой очереди или NULL, если элемент последний.

Макрос STAILQ_REMOVE_HEAD удаляет элемент из начала хвостовой очереди. В целях эффективности удаления элемента из начала хвостовой очереди нужно использовать именно этот макрос вместо обычного STAILQ_REMOVE.

Макрос STAILQ_REMOVE удаляет элемент elm из хвостовой очереди.

  Пример односвязной хвостовой очереди

    STAILQ_HEAD(stailhead, entry) head =
        STAILQ_HEAD_INITIALIZER(head);
    struct stailhead *headp;		/* начало односвязной хвостовой
                                   очереди */
    struct entry {
    	...
    	STAILQ_ENTRY(entry) entries;	/* хвостовая очередь */
    	...
    } *n1, *n2, *n3, *np;
    STAILQ_INIT(&head);			/* инициализация очереди */
    n1 = malloc(sizeof(struct entry));	/* вставка начального элемента */
    STAILQ_INSERT_HEAD(&head, n1, entries);
    n1 = malloc(sizeof(struct entry));	/* вставка в очередь */
    STAILQ_INSERT_TAIL(&head, n1, entries);
    n2 = malloc(sizeof(struct entry));	/* вставка последующего */
    STAILQ_INSERT_AFTER(&head, n1, n2, entries);
    					/* удаление */
    STAILQ_REMOVE(&head, n2, entry, entries);
    free(n2);
    					/* удаление из начала */
    n3 = STAILQ_FIRST(&head);
    STAILQ_REMOVE_HEAD(&head, entries);
    free(n3);
    					/* обход от начала в конец */
    STAILQ_FOREACH(np, &head, entries)
    	np-> ...
    					/* удаление TailQ */
    while (!STAILQ_EMPTY(&head)) {
    	n1 = STAILQ_FIRST(&head);
    	STAILQ_REMOVE_HEAD(&head, entries);
    	free(n1);
    }
    					/* быстрое удаление TailQ */
    n1 = STAILQ_FIRST(&head);
    while (n1 != NULL) {
    	n2 = STAILQ_NEXT(n1, entries);
    	free(n1);
    	n1 = n2;
    }
    STAILQ_INIT(&head);

  Списки
Список начинается структурой, определённой макросом LIST_HEAD. Эта структура содержит единственный указатель на первый элемент списка. Элементы дважды связаны, поэтому произвольный элемент можно удалить без прохода по всему списку. Новые элементы могут быть добавлены в список перед или после существующего элемента, а также в начало списка. Структура LIST_HEAD объявляется следующим образом:

    LIST_HEAD(HEADNAME, TYPE) head;

где HEADNAME — имя определяемой структуры, а TYPE — тип элементов, объединяемых в список. Указатель на начало списка может в дальнейшем объявляться так:

    struct HEADNAME *headp;

(Имена head и headp могут выбираться пользователем.)

Макрос LIST_HEAD_INITIALIZER запускает инициализатор для head списка.

Макрос LIST_EMPTY возвращает true, если в списке нет элементов.

Макрос LIST_ENTRY объявляет структуру, которая добавляет элементы в список.

Макрос LIST_FIRST возвращает первый элемент списка или NULL, если список пуст.

Макрос LIST_FOREACH обходит список, на который ссылается head, от начало в конец, назначая var каждый элемент.

Макрос LIST_INIT инициализирует список, на который ссылается head.

Макрос LIST_INSERT_HEAD вставляет новый элемент elm в начало списка.

Макрос LIST_INSERT_AFTER вставляет новый элемент elm за элементом listelm.

Макрос LIST_INSERT_AFTER вставляет новый элемент elm перед элементом listelm.

Макрос LIST_NEXT возвращает следующий элемент списка или NULL, если элемент последний.

Макрос LIST_REMOVE удаляет элемент elm из списка.

  Пример списка

    LIST_HEAD(listhead, entry) head =
        LIST_HEAD_INITIALIZER(head);
    struct listhead *headp;			/* начало списка */
    struct entry {
    	...
    	LIST_ENTRY(entry) entries;	/* список */
    	...
    } *n1, *n2, *n3, *np, *np_temp;
    LIST_INIT(&head);			/* инициализация списка */
    n1 = malloc(sizeof(struct entry));	/* вставка в начало */
    LIST_INSERT_HEAD(&head, n1, entries);
    n2 = malloc(sizeof(struct entry));	/* вставка последующего */
    LIST_INSERT_AFTER(n1, n2, entries);
    n3 = malloc(sizeof(struct entry));	/* вставка перед */
    LIST_INSERT_BEFORE(n2, n3, entries);
    LIST_REMOVE(n2, entries);		/* удаление */
    free(n2);
    					/* обход из начала в конец */
    LIST_FOREACH(np, &head, entries)
    	np-> ...
    while (!LIST_EMPTY(&head)) {		/* удаление списка */
    	n1 = LIST_FIRST(&head);
    	LIST_REMOVE(n1, entries);
    	free(n1);
    }
    n1 = LIST_FIRST(&head);			/* быстрое удаление списка */
    while (n1 != NULL) {
    	n2 = LIST_NEXT(n1, entries);
    	free(n1);
    	n1 = n2;
    }
    LIST_INIT(&head);

  Хвостовые очереди
Хвостовая очередь начинается со структуры, определяемой макросом TAILQ_HEAD. Эта структура содержит пару указателей, один для первого элемента хвостовой очереди, а другой для последнего элемента хвостовой очереди. Элементы связаны дважды так, что любой элемент может быть удалён без прохождения по всей очереди. Новые элементы могут быть добавлены в хвостовую очередь перед и после существующего элемента, в конец или в начало очереди. Структура TAILQ_HEAD объявляется следующим образом:

    TAILQ_HEAD(HEADNAME, TYPE) head;

где HEADNAME — имя определяемой структуры, а TYPE — тип связанных элементов в хвостовой очереди. Указатель на начало хвостовой очереди может в дальнейшем объявляться так:

    struct HEADNAME *headp;

(Имена head и headp могут выбираться пользователем.)

Макрос TAILQ_HEAD_INITIALIZER запускает инициализатор для head хвостовой очереди.

Макрос TAILQ_CONCAT добавляет хвостовую очередь с началом head2 в конец очереди с началом head1, удаляя все элементы из первой.

Макрос TAILQ_EMPTY возвращает true, если в хвостовой очереди нет элементов.

Макрос TAILQ_ENTRY объявляет структуру, которая подключает элементы в хвостовую очередь.

Макрос TAILQ_FIRST возвращает первый элемент из хвостовой очереди или NULL, если очередь пуста.

Макрос TAILQ_FOREACH обходит хвостовую очередь, на которую ссылается head, из начала в конец, назначая var каждый элемент. Значение var равно NULL, если пройдена вся очередь или в ней нет элементов.

Макрос TAILQ_FOREACH_REVERSE обходит хвостовую очередь, на которую ссылается head, в обратном направлении, назначая var каждый элемент.

Макрос TAILQ_INIT инициализирует хвостовую очередь, на которую ссылается head.

Макрос TAILQ_INSERT_HEAD вставляет новый элемент I elm в начало хвостовой очереди.

Макрос TAILQ_INSERT_TAIL вставляет новый элемент elm в конец хвостовой очереди.

Макрос TAILQ_INSERT_AFTER вставляет новый элемент elm за элементом listelm.

Макрос TAILQ_INSERT_BEFORE вставляет новый элемент elm перед элементом listelm.

Макрос TAILQ_LAST возвращает последний элемент из хвостовой очереди или NULL, если очередь пуста.

Макрос TAILQ_NEXT возвращает следующий элемент из хвостовой очереди или NULL, если элемент последний.

Макрос TAILQ_PREV возвращает предыдущий элемент из хвостовой очереди или NULL, если элемент первый.

Макрос TAILQ_REMOVE удаляет элемент elm из хвостовой очереди.

Макрос TAILQ_SWAP меняет местами содержимое head1 и head2.

  Пример хвостовой очереди

    TAILQ_HEAD(tailhead, entry) head =
        TAILQ_HEAD_INITIALIZER(head);
    struct tailhead *headp;			/* начало хвостовой очереди */
    struct entry {
    	...
    	TAILQ_ENTRY(entry) entries;	/* хвостовая очередь */
    	...
    } *n1, *n2, *n3, *np;
    TAILQ_INIT(&head);			/* инициализация очереди */
    n1 = malloc(sizeof(struct entry));	/* вставка в начало */
    TAILQ_INSERT_HEAD(&head, n1, entries);
    n1 = malloc(sizeof(struct entry));	/* вставка в конец */
    TAILQ_INSERT_TAIL(&head, n1, entries);
    n2 = malloc(sizeof(struct entry));	/* вставка последующего */
    TAILQ_INSERT_AFTER(&head, n1, n2, entries);
    n3 = malloc(sizeof(struct entry));	/* вставка перед */
    TAILQ_INSERT_BEFORE(n2, n3, entries);
    TAILQ_REMOVE(&head, n2, entries);	/* удаление */
    free(n2);
    					/* обход из начало в конец */
    TAILQ_FOREACH(np, &head, entries)
    	np-> ...
    					/* обход в обратном направлении */
    TAILQ_FOREACH_REVERSE(np, &head, tailhead, entries)
    	np-> ...
    					/* удаление TailQ */
    while (!TAILQ_EMPTY(&head)) {
    	n1 = TAILQ_FIRST(&head);
    	TAILQ_REMOVE(&head, n1, entries);
    	free(n1);
    }
    					/* быстрое удаление TailQ */
    n1 = TAILQ_FIRST(&head);
    while (n1 != NULL) {
    	n2 = TAILQ_NEXT(n1, entries);
    	free(n1);
    	n1 = n2;
    }
    TAILQ_INIT(&head);
    n2 = malloc(sizeof(struct entry));  /* вставка перед */
    CIRCLEQ_INSERT_BEFORE(&head, n1, n2, entries);
                                        /* обход из начала в конец */
    for (np = head.cqh_first; np != (void *)&head;
            np = np->entries.cqe_next)
        np-> ...
                                        /* обход в обратном направлении */
    for (np = head.cqh_last; np != (void *)&head; np = np->entries.cqe_prev)
        np-> ...
                                        /* удаление */
    while (head.cqh_first != (void *)&head)
        CIRCLEQ_REMOVE(&head, head.cqh_first, entries);

СООТВЕТСТВИЕ СТАНДАРТАМ
Нет в POSIX.1, POSIX.1-2001 и POSIX.1-2008. Присутствует в BSD. Функции queue впервые появились в 4.4BSD.