我们阅读一下contiki的源码,list.c(路径是./core/lib/list.h).
#include "lib/list.h" #define NULL 0 struct list { struct list *next; };
这就是核心结构体了,发现了吗?没有数据域,成员就是一个指针。其实这个有点类似Linux里面的链表,对,就是嵌入在结构体里面的那个list.我们继续往下看。
void list_init(list_t list) { *list = NULL; }
初始化函数,这里要说明的是,list_t 就是void**类型。
在头文件中,有这样的定义:
#define LIST_CONCAT2(s1, s2) s1##s2 #define LIST_CONCAT(s1, s2) LIST_CONCAT2(s1, s2)
#define LIST(name) static void *LIST_CONCAT(name,_list) = NULL; static list_t name = (list_t)&LIST_CONCAT(name,_list)
其实就是定义一个链表(假设name是hello). 有个变量叫hello_list, 其实是一个void*类型的指针,初始化为NULL,这个链表的名字叫hello, hello是指向hello_list的二级指针。
这里的list是没有头节点的,*hello就得到了第一个元素。因为每个元素都是指针,那么初始化的时候,第一个元素自然为NULL了,表示链表为空。
void * list_head(list_t list) { return *list; }返回链表的第一个元素。
void * list_tail(list_t list) { struct list *l; if(*list == NULL) { return NULL; } for(l = *list; l->next != NULL; l = l->next); return l; }返回链表的最后一个元素。
void list_remove(list_t list, void *item) { struct list *l, *r; if(*list == NULL) { return; } r = NULL;//r用来保存前一个元素 for(l = *list; l != NULL; l = l->next) { if(l == item) { if(r == NULL) {//说明要删除的元素恰好是第一个 /* First on list */ *list = l->next; } else { /* Not first on list */ r->next = l->next; } l->next = NULL; return; } r = l; } }删除某个元素。(千万要记住,这个链表的元素就是指针!)
void list_add(list_t list, void *item) { struct list *l; /* Make sure not to add the same element twice */ list_remove(list, item); ((struct list *)item)->next = NULL; l = list_tail(list);//得到最后一个元素 if(l == NULL) { *list = item; } else { l->next = item; } }把元素追加到末尾。
void list_push(list_t list, void *item) { /* Make sure not to add the same element twice */ list_remove(list, item); ((struct list *)item)->next = *list; *list = item; }头插元素。
void * list_chop(list_t list) { struct list *l, *r; if(*list == NULL) { return NULL; } if(((struct list *)*list)->next == NULL) {//说明只有一个元素 l = *list; *list = NULL; return l; } for(l = *list; l->next->next != NULL; l = l->next);//查找到倒数第二个元素 r = l->next; l->next = NULL; return r; }”弹出“最末尾的一个元素。
void * list_pop(list_t list) { struct list *l; l = *list; if(*list != NULL) { *list = ((struct list *)*list)->next; } return l; }“弹出”第一个元素。
其他函数代码都很简单,我们不再赘述。
有的朋友不禁要问了,这样的一个链表,怎么用呢?答案下次揭晓,下次我们结合内存管理,举例说明这个链表的用法。