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");
}
View Code

相关文章: