Hello,
the TAILQ_LAST and TAILQ_PREV macros in sys/queue.h only
work because by coincidence the head and the entry struct are
similar (they both have 2 pointers: struct type* and struct type**).
If you insert a char dummy in between:
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
char dummy; \
struct type **tqe_prev; /* address of previous next element */ \
}
then the test program below will crash:
pref:afarber> cat tailq.c
/* gcc -DQUEUE_MACRO_DEBUG tailq.c -o tailq */
#include <stdio.h>
#include <sys/queue.h>
typedef struct element {
TAILQ_ENTRY(element) field;
int i;
} element;
TAILQ_HEAD(headname, element) head = TAILQ_HEAD_INITIALIZER(head);
int
main(int argc, char* argv[])
{
int i;
element *pe;
for (i = 0; i < 10; i++) {
if ((pe = (element*) malloc(sizeof(*pe))) == NULL)
err(1, NULL);
pe->i = i;
TAILQ_INSERT_TAIL(&head, pe, field);
}
printf("TAILQ_FOREACH:\n");
TAILQ_FOREACH(pe, &head, field) {
printf("%d\n", pe->i);
}
printf("TAILQ_FOREACH_REVERSE:\n");
TAILQ_FOREACH_REVERSE(pe, &head, headname, field) {
printf("%d\n", pe->i);
}
printf("TAILQ_LAST:\n");
pe = TAILQ_LAST(&head, headname);
printf("%d\n", pe->i);
return 0;
}
pref:afarber> gcc -DQUEUE_MACRO_DEBUG tailq.c -o tailq
pref:afarber> ./tailq
TAILQ_FOREACH:
0
1
2
3
4
5
6
7
8
9
TAILQ_FOREACH_REVERSE:
Segmentation fault (core dumped)
Also the TAILQ_LAST macro cheats by taking a (head)->tqh_last
and saying that it's a pointer to the last element. But in fact it's a
pointer to the tqe_next member of the last element. This works only
because that member is the 1st one in that structure.
IMHO a solution would be to change the head structure to hold
just that: the pointer to the last element (which is needed above):
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type *tqh_last; /* addr of last element */ \
}
By fixing those 2 issues the headname argument of the 3 macros
TAILQ_LAST, TAILQ_PREV and TAILQ_FOREACH_REVERSE
could be dropped...
Am I wrong?
Regards
Alex
--
http://preferans.de