Linux内核中List链表的实现,对于想进阶的程序员来说,无疑是一个很好的学习机会。内核实现了一个功能十分强大的链表,而且是开源的,用在其他需要的地方岂不是很省事。
一、看List实现前,先补充typeof的知识,方便阅读。
typeof(int *) p1, p2; /* Declares two int pointers p1, p2 */ int *p1, *p2; typeof(int) * p3, p4;/* Declares int pointer p3 and int p4 */ int * p3, p4;extern int foo(); typeof(foo()) var;
typeof(foo())var; 等效于typeof(int) var; 也就等效于 int var; 同时foo()函数也不会被执行。
typeof构造的主要应用是用在宏定义中,可以使用typeof关键字来引用宏参数的类型。
二、如何自己在非Linux环境下使用双向List。
将这段代码移植到一般的C程序,那么基本上要实现这么几个功能。1、初始化List头。 2、向List中添加一个节点到首节点后 3、向List中添加一个节点到首节点前 4、从List中删除一个节点 5、从List中取出一个节点,但节点在List中不删除。 6、遍历List Linux内核中的List功能做得那么完善,需要的时候再看看。7、判断链表是否为空。
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifndef ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCH static void prefetch(const void *x) {;} #endif struct list_head { struct list_head *next, *prev; }; #define list_entry(ptr, type, member) container_of(ptr, type, member) #define offsetof(TYPE, MEMBER) ((size_t)& ((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) (type*)((char *)ptr - offsetof(type,member)) #define list_for_each(pos, head) \ for (pos = (head)->next; prefetch(pos->next), pos != (head); \ pos = pos->next) #define LIST_HEAD_INIT(name) { &(name), &(name) } //prev和next都指向自己 //prev和next都指向自己 static void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } //new在编译器里被认作关键字 原代码是new 被改为l_new //l_new 是要被插入的节点 //prev 是插入点前面的一个节点 //next 是插入点后面的一个节点 static void __list_add(struct list_head *l_new, struct list_head *prev, struct list_head *next) { next->prev = l_new; l_new->next = next; l_new->prev = prev; prev->next = l_new; } //这个函数对上面简化 新加入的节点在head和head->next之间 也就是head之后 static void list_add(struct list_head *l_new, struct list_head *head) { __list_add(l_new, head, head->next); } //这个函数对上面简化 新加入的节点在head->prev和head之间 也就是head之前 static void list_add_tail(struct list_head *l_new, struct list_head *head) { __list_add(l_new, head->prev, head); } //删除一个双向列表中的一个节点 删除节点在prev和next之间 static void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } //从列表中删除entry节点,这个函数是对上面函数的简化 //entry->next = LIST_POISON1; //entry->prev = LIST_POISON2; static void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = NULL; //这两个指针可以不处理,如果从list中del掉了一个节点, entry->prev = NULL; //接下来 这个节点就要被删除 } //跟上面函数功能一样,将entry中队列里删除后,初始化entry为队列头 static void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } //判断list是不是最后一个节点 //head节点是队列的第一个节点 //return list->next == head 或者 return head->prev == list一样 static int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } //列表是不是为空 //head节点 是队列的头节点 static int list_empty(const struct list_head *head) { return head->next == head; } //建立一个数据结构 typedef struct Student { int id; //学号 char name[16]; //姓名 struct list_head list; }Student; void main(void) { int i=0; char c_tmp[16]={0}; Student* p; struct list_head *n,*pos; Student stdudent_head; //用作列表头 INIT_LIST_HEAD(&stdudent_head.list); //初始化列表头 if(list_empty(&stdudent_head.list)) //如果是空,返回1 { printf("Now List is Empty!\n"); } for(i=0;i<5;i++) { p = (Student* )malloc(sizeof(Student)); p->id = i+1; memset(c_tmp,0,16); sprintf((char*)c_tmp,"MYNAME-%d",i+1); strcpy((char*)(p->name),(char*)c_tmp); list_add_tail(&p->list,&stdudent_head.list); //依次添加5个节点到队列中 } list_for_each(pos, &stdudent_head.list) { p = list_entry(pos,Student,list); printf("----------------------------\n"); printf("id = %d\n",p->id); printf("name = %s\n",p->name); printf("----------------------------\n"); } printf("test end-------------!\n"); system("pause"); }