On 14/10/2016 12:44, Dr. David Alan Gilbert wrote: >> > +#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) do { >> > \ >> > + *((void **) ((char *) (elm) + (entry) + QTAILQ_NEXT_OFFSET)) = >> > NULL; \ >> > + *((void **) ((char *) (elm) + (entry) + QTAILQ_PREV_OFFSET)) = >> > \ >> > + *((void **) ((char *) (head) + QTAILQ_LAST_OFFSET)); >> > \ >> > + **((void ***)((char *) (head) + QTAILQ_LAST_OFFSET)) = (elm); >> > \ >> > + *((void **) ((char *) (head) + QTAILQ_LAST_OFFSET)) = >> > \ >> > + (void *) ((char *) (elm) + (entry) + QTAILQ_NEXT_OFFSET); >> > \ >> > +} while (/*CONSTCOND*/0) > I wonder if there's a simpler way to do this; I'm not sure this works, but > something like: > > struct QTAILQDummy { > char dummy; > }; > > QTAILQ_HEAD(QTAILQRawHead, struct QTAILQDummy) > typedef QTAILQ_ENTRY(struct QTAILQDummy) QTAILQRawEntry; > > #define QTAILQ_RAW_FOREACH(elm, head, entry) > \ > for ((elm) = ((struct QTAILQRawHead *)head)->tqh_first) > \ > (elm); > \ > (elm) = > \ > (elm) = ((QTAILQRawEntry *)((char *) (elm) + (entry)))->tqh_next > > and then I think elm gets declared as a struct QTAILQDummy. > But it does avoid those FIRST_OFFSET/LAST_OFFSET/NEXT_OFFSET/PREV_OFFSET > calculations.
Another possibility is a macro like #define field_at_offset(base, offset, type) \ ((type) (((char *) (base)) + (offset))) so that you can do *field_at_offset(void **, elm, (entry) + QTAILQ_NEXT_OFFSET) = NULL; *field_at_offset(void ***, elm, (entry) + QTAILQ_PREV_OFFSET) = *field_at_offset(void ***, head, QTAILQ_LAST_OFFSET); **field_at_offset(void ***, head, QTAILQ_LAST_OFFSET) = (elm); *field_at_offset(void ***, head, QTAILQ_LAST_OFFSET) = field_at_offset(void **, elm, (entry) + QTAILQ_NEXT_OFFSET); or something like that (note that I've always used the same type for next and last, by the way). Paolo