【问题标题】:What does (*(QUEUE **) &((*(q))[0])) mean in libuv, or How does the queue work?(*(QUEUE **) &((*(q))[0])) 在 libuv 中是什么意思,或者队列是如何工作的?
【发布时间】:2020-04-11 12:10:33
【问题描述】:

我刚刚进入 C 中的 void 指针和双指针等尝试使事情动态化。然后我遇到了this,如下所示:

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_NEXTQUEUE_PREV,做了某种魔术。

【问题讨论】:

  • 看看this example,应该会有所帮助。基本上,队列中的任何结构都必须包含一个QUEUE 元素,该元素用于将元素链接在一起形成一个循环的双向链。 QUEUE_DATA 宏用于从指向其QUEUE 元素的指针访问原始结构。

标签: c arrays pointers queue libuv


【解决方案1】:

它是一个循环链表的接口。当您解决第一个宏用法时,您会得到:

  • 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] 相同

这当然只有在wqQUEUE 类型时才有效,这只是一个由两个空指针组成的数组。作者求助于void*,因为afaik 在C 中不可能typedef 一个指向自身的指针数组。

QUEUE_INSERT_TAIL btw 是拼接两个列表的代码。这个界面的有趣之处在于,你如何获得每个元素的内容?看看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)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 2020-01-07
    • 2018-09-10
    • 2017-05-09
    相关资源
    最近更新 更多