我只是在 C 中进入空指针和双指针等,以尝试使事情动态化。然后我遇到了这个,如下所示:
typedef void *QUEUE[2];
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
有太多的指针、参数和参考资料在我眼前。想知道是否有人可以解释:
- 该部分
(*(QUEUE **) &((*(q))
在做什么,以及 - 此队列如何只能有两个项目。
这是如何工作的? 具体来说,他们有这个:
#define QUEUE_INSERT_TAIL(h, q)
do {
QUEUE_NEXT(q) = (h);
QUEUE_PREV(q) = QUEUE_PREV(h);
QUEUE_PREV_NEXT(q) = (q);
QUEUE_PREV(h) = (q);
}
while (0)
这QUEUE_INSERT_TAIL
如何运作?
或者例如,我也有兴趣知道这是怎么回事:
#define QUEUE_INIT(q)
do {
QUEUE_NEXT(q) = (q);
QUEUE_PREV(q) = (q);
}
while (0)
...
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->idle_handles);
QUEUE_INIT(&loop->async_handles);
QUEUE_INIT(&loop->check_handles);
QUEUE_INIT(&loop->prepare_handles);
QUEUE_INIT(&loop->handle_queue);
最后,他们都在内部使用QUEUE_NEXT
和QUEUE_PREV
,做某种魔法。
它是循环链表的接口。解决第一个宏用法时,您将获得:
QUEUE_NEXT(&loop->wq)
->*(QUEUE **) &((*( &loop->wq ))[0])
->*(QUEUE **) &(( loop->wq )[0])
->*(QUEUE **) &( loop->wq[0] )
->*(QUEUE **) &loop->wq[0]
这实际上与(QUEUE *)( loop->wq[0] )
相同或只是loop->wq[0]
当然,这只有在wq
类型为QUEUE
时才有效,它只不过是一个由两个 void 指针组成的数组。作者求助于void*
因为 afaik 在 C 中不可能对指向自身的指针数组进行 typedef。
顺便说一句QUEUE_INSERT_TAIL
是拼接两个列表的代码。这个界面的有趣之处在于,你如何获得每个元素的内容?看看QUEUE_DATA
的定义
#define QUEUE_DATA(ptr, type, field)
((type *) ((char *) (ptr) - ((long) &((type *) 0)->field)))
它的用法
struct user_s {
int age;
char* name;
QUEUE node;
};
user = QUEUE_DATA(q, struct user_s, node);
这解析为
QUEUE_DATA(q, struct user_s, node)
->(struct user_s*) ((char *) (q) - ((long) &((struct user_s*) 0)->node))
它通过减去其QUEUE
成员的偏移量来有效地将地址返回给包含结构,因此q
的值将调整为它指向的结构(此处user_s
)的地址。