走读libuv源代码。可以看到如下定义:
typedef void *QUEUE[2];
/* Private macros. */
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
QUEUE是一个void*的指针数组。数组个数为2.
其实可以类比一下。
typedef int A[]; // A 是 int[]
A a = {1, 2}; // a 的类型是 int[2]
A b = {3,4,5}; // b 的类型是 int[3]
这样是不是就理解了。
这样做是为了操作uv_loop_s中的变量hande_queue[2],active_reqs[2]、
void * hande_queue[2];等价于QUEUE handle_queue
struct uv_loop_s {
/* User data - use this for whatever. */
void* data;
/* Loop reference counting. */
unsigned int active_handles;
void* handle_queue[2];
void* active_reqs[2];
/* Internal flag to signal loop stop. */
unsigned int stop_flag;
UV_LOOP_PRIVATE_FIELDS
};
再看一个具体的使用的实例:
//为啥用do while,因为c中只有这个能保证宏在任何的扩展中不被破坏整个宏的语义。
//具体可以再查阅。
#define QUEUE_INIT(q) \
do { \
QUEUE_NEXT(q) = (q); \
QUEUE_PREV(q) = (q); \
} \
while (0)
使用这个宏初始化变量。
QUEUE_INIT(&loop->handle_queue);
这句话怎么解释呢。
(*(QUEUE **) &((*(&loop->handle_queue))[0]))
取handle_queue数组的第一个数据地址,强转成QUEUE**类型不丢失类型信息。再用*取值,可以放在=好左侧
调用这个初始化后就是指向了自己