链表(list)的宏定义实现

-- 看代码是一种享受

 

  最近在看DHCP的源码,一些好的记录下来。平时写C,用到链表就是copy数据结构上的代码,简单粗暴,今天换种方式,看下宏定义实现的链表,好处自然是代码少、效率高。

 

  首先下面链表宏定义的实现,摘自wide-dhcpv6-20080615源码包/* * List declarations. */ #define LIST_HEAD(name, type) / struct name { / struct type *lh_first; /* first element */ / } #define LIST_ENTRY(type) / struct { / struct type *le_next; /* next element */ / struct type **le_prev; /* address of previous next element */ / } /* * List functions. */ #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) #define LIST_INIT(head) do { / LIST_FIRST((head)) = NULL; / } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { / if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) / LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);/ LIST_FIRST((head)) = (elm); / (elm)->field.le_prev = &LIST_FIRST((head)); / } while (0) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_REMOVE(elm, field) do { / if (LIST_NEXT((elm), field) != NULL) / LIST_NEXT((elm), field)->field.le_prev = / (elm)->field.le_prev; / *(elm)->field.le_prev = LIST_NEXT((elm), field); / } while (0)  

  比较难理解的可能是LIST_ENTRY中的成员le_prev,它不是平时双向链表中的前向指针(指向前一个元素),而是前向前一个元素的le_next成员的指针(可能比较绕口,下面看图更清楚)。

            

  上图显示了链表头插入两个元素: elem-1和elem-2后指针的指向,注意le_prev指向的是指针的地址,而不是元素的地址。

 

  下面逐一分析:

   1. 声明链表的一项entry结构体, 包含两个成员:计数值(链表的数据部分)counter和指向前后的指针link

                struct sn_entry { TAILQ_ENTRY(sn_entry) link; int counter; };

   2. 声明链表头sn_head

               TAILQ_HEAD(, sn_entry) sn_head;

                 可能不大好理解,将宏定义展开就很清晰了,其实就是定义了链表头

     struct { / struct sn_entry *lh_first; /* first element */ / } sn_head;

       3. 链表的初始化

               TAILQ_INIT(&sn_head);

   4. 再就是使用了,包括了插入、删除、枚举,就不一一列举了

                               

     

        插入做的就是改变前后指针,假如将元素elem2插入到elem1后,elem3前,则将elem1的le_next指针指向elem2,elem2的le_next指针指向elem3;将elem2的le_prev指针指向elem1的成员le_next,将elem3的le_prev指针指向elem2的成员le_next

        删除做的也是改变前后指针,假如从elem1和elem3间删除elem2,则将elem1的le_next指针指向elem3,elem3的le_prev指向elem1的le_next成员

枚举就是顺着链表头向下,仅使用le_next成员即可

你可能感兴趣的:(数据结构,c,struct,list,null,insert)