libevent中的tailq本质上, 就是一个双向链表, 而后记录下了头指针和尾指针, 便于顺序遍历和逆序遍历.spa
因为C语言中没有模板, 为了适应不一样的数据类型, tailq的操做, 都是使用的宏定义, 致使代码难以阅读.指针
为了方便分析, 本文对tailq相关的结构体进行了简化:code
struct tailq{ struct element* first; struct element** last; };
struct element{ struct element* next; //next必须放在第一个位置 struct element** prev; int x;//这里表示结构体中的其它成员 };
读者可能有如下一些疑问:element
1. last和prev为何要使用指针地址, 直接用struct element*不是更简洁明了吗?event
看下面这段代码: ast
struct element** prev; struct element* elem = malloc(sizeof(struct element)); prev = &elem->next;
根据C语言的规则模板
由于elem == &elem->nextclass
因此: prev == elem效率
即: next的值elem指针, prev的值也是elem的指针, 只不过形式上是struct element**, 使用时, 能够直接强转为struct elemnt*来操做遍历
写了一个普通的双向链表, 与之对比, 得出的结论是, tailq使用指针地址方式, insert_tail的操做少了一条if语句判断, 效率上更优.
2. 数据存储的结构是怎样的, 根据代码表面上的意义, 能够画出这样一张图:
绿色表示整个element
蓝色表示字段
白色表示值
因为&next的值, 等于element指针, 因此上图能够演变成
这样, 就很清晰了, prev指向前一个元素, next指向后一个元素, first指向第一人元素, last指向最后一个元素