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