对WDK中对LIST_ENTRY的操作的相关函数的实现及简单运用

  这篇文章主要是描述WDK中对LIST_ENTRY双向链表的操作的相关函数(不包含原子操作)的实现以及使用范例.
  代码中我用一个结构体+函数指针的方式把函数给包裹了一下,看不惯的可以直接调用原函数即可.
  如果不懂CONTAINING_RECORD,参见:我对CONTAINING_RECORD宏的详细解释(http://www.cnblogs.com/nbsofer/archive/2013/01/07/2849913.html)

  关键词:WDK,LIST_ENTRY,CONTAINING_RECORD

  2013-07-14 更新:加入了list_remove函数,实现移除双向链表中的某一结点

#ifndef __LIST_H__
#define __LIST_H__

/**********************************************************
文件名称:list.h/list.c
文件路径:../list/list.h,../list/list.c
创建时间:2013-1-29,0:23:04
文件作者:女孩不哭
文件说明:该头文件及实现文件实现了WDK中双向链表的操作函数
2013-07-13 更新:加入list_remove函数实现移除某一结点
**********************************************************/

#ifdef __cplusplus
extern "C" {
#endif

typedef struct _list_s{
    struct _list_s* prior;
    struct _list_s* next;
}list_s;

struct _my_list{
    int   (*is_empty)(list_s* phead);
    void  (*init)(list_s* phead);
    void  (*insert_head)(list_s* phead, list_s* plist);
    void  (*insert_tail)(list_s* phead, list_s* plist);
    list_s* (*remove_head)(list_s* phead);
    list_s* (*remove_tail)(list_s* phead);
    int (*remove)(list_s* phead,list_s* p);
};

//该宏实现根据结构体中链表的指针得到结构体的指针
//为CONTAINING_RECORD宏的实现
#define list_data(addr,type,member) \
    ((type*)(((unsigned char*)addr)-(unsigned long)&(((type*)0)->member)))

#ifdef __list_c__
#undef __list_c__

static int   list_is_empty(list_s* phead);
static void  list_init(list_s* phead);
static void  list_insert_head(list_s* phead, list_s* plist);
static void  list_insert_tail(list_s* phead, list_s* plist);
static list_s* list_remove_head(list_s* phead);
static list_s* list_remove_tail(list_s* phead);
static int list_remove(list_s* phead,list_s* p);

#else

extern struct _my_list* list;

#endif//!__list_c__

#ifdef __cplusplus
}
#endif//!__cplusplus

#endif//!__LIST_H__
#include <stdio.h>
#define  __list_c__
#include "list.h"

struct _my_list _inner_list = {
    list_is_empty,
    list_init,
    list_insert_head,
    list_insert_tail,
    list_remove_head,
    list_remove_tail,
    list_remove
};
struct _my_list* list = &_inner_list;

/**************************************************
函  数:list_is_empty@4
功  能:判断双向链表是否为空
参  数:phead - 双向链表头指针
返回值:非零表示为空,零表示不为空
说  明:
**************************************************/
int list_is_empty(list_s* phead)
{
    return phead->next == phead;
}

/**************************************************
函  数:list_init@4
功  能:初始化双向链表为空
参  数:phead - 链表头指针
返回值:(无)
说  明:
**************************************************/
void list_init(list_s* phead)
{
    //使前后指针都指向自己(头结点)
    //即为空链表
    phead->prior = phead;
    phead->next = phead;
}

/**************************************************
函  数:list_insert_head@8
功  能:从双向链表头部插入结点
参  数: phead - 链表头指针
        plist - 待插入的链表结点指针
返回值:(无)
说  明:
**************************************************/
void list_insert_head(list_s* phead, list_s* plist)
{
    //得到第1个结点的指针
    //为空链表时也满足
    list_s* first = phead->next;
    //在头结点和第1个结点之间插入时需要:
    //  头结点的prior不变;头结点的next指向新结点
    //  新结点的prior指向头结点;新结点的next指向第1个结点
    //  第1个结点的prior指向新结点;第1个结点的next不变
    phead->next = plist;
    plist->prior = phead;
    plist->next = first;
    first->prior = plist;
}

/**************************************************
函  数:list_insert_tail@8
功  能:从双向链表尾部插入结点
参  数: phead - 链表头指针
        plist - 待插入的链表结点指针
返回值:(无)
说  明:
**************************************************/
void list_insert_tail(list_s* phead, list_s* plist)
{
    //得到最后一个结点的指针
    //为空链表时也满足
    list_s* last = phead->prior;
    //在最后一个结点和头结点之间插入时需要:
    //  最后一个结点的next指向新结点;最后一个结点的prior不变
    //  新结点的prior指向最后一个结点;新结点的next指向头结点
    //  头结点的next不变;头结点的prior指向新结点
    last->next = plist;
    plist->prior = last;
    plist->next = phead;
    phead->prior = plist;
}

/**************************************************
函  数:list_remove_head@4
功  能:从双向链表头部移除结点
参  数:phead - 链表头指针
返回值:被移除的结点指针
    若链表为空,返回NULL
说  明:
**************************************************/
list_s* list_remove_head(list_s* phead)
{
    list_s* second = NULL;
    list_s* removed = NULL;
    if(list_is_empty(phead))
        return NULL;
    //需要移除第1个结点,则应该先保存第2个结点
    //若不存在第2个结点也满足条件(此时second即为头结点)
    second = phead->next->next;
    removed = phead->next;
    //移除第1个结点需要:
    //  头结点的next指向第2个结点(若不存在,则指向自己);头结点的prior不变
    //  第2个结点的prior指向头结点;第2个结点的next不变
    phead->next = second;
    second->prior = phead;
    return removed;
}

/**************************************************
函  数:list_remove_tail@4
功  能:从双向链表尾部移除结点
参  数:phead - 链表头指针
返回值:被移除的结点指针
    若链表为空,返回NULL
说  明:
**************************************************/
list_s* list_remove_tail(list_s* phead)
{
    list_s* second_last = NULL;
    list_s* removed = NULL;
    if(list_is_empty(phead))
        return NULL;
    //需要移除最后一个结点,需要保存倒数第2个结点指针
    //若不存在倒数第2个(仅一个结点时),倒数第2个就是头结点
    second_last = phead->prior->prior;
    removed = phead->prior;
    //移除一个结点需要
    //  倒数第2个结点的next指向头结点,prior不变
    //  头结点的prior指向倒数第2个结点,next不变
    second_last->next = phead;
    phead->prior = second_last;
    return removed;
}

/**************************************************
函  数:list_remove
功  能:移除结点指针为p的结点
参  数: p - 待移除的结点
        phead - 链接头结点
返  回: 0 - 无此结点
        1 - 成功
        2 - 链表为空
说  明:
**************************************************/
int list_remove(list_s* phead,list_s* p)
{
    if(!list_is_empty(phead)){
        list_s* node = NULL;
        for(node=phead->next; node!=phead; node=node->next){
            if(node == p){
                //移除该结点需要:
                // 将当前结点的上一个结点:
                //      next指向当前结点的next
                // 将当前结点的下一个结点:
                //      prior指向当前结点的上一个结点
                node->prior->next = node->next;
                node->next->prior = node->prior;
                return 1;
            }
        }
        return 0;
    }else{
        return 2;
    }
}

 

 

下面这个是使用范例:

//main.c
#include <stdio.h>
#include <stdlib.h>
#include "list.h"

#define array_size(array) (sizeof(array)/sizeof(array[0]))

//自己定义的数据结构体类型
//要包含list_s结构体类型变量
//list_s变量位置任意
typedef struct{
    int num;
    list_s list_entry;
}my_data;

int main(void)
{
    list_s list_head;
    //为了简便,我直接使用局部数组数据
    my_data md[16];
    int it1,it2;
    //这里保存了4种方式遍历时的函数指针相关信息
    struct{
        void (*insert)(list_s*,list_s*);
        list_s* (*remove)(list_s*);
        char* msg;
    } func_ptr[] = {
        {list->insert_head,list->remove_head,"头头"},
        {list->insert_head,list->remove_tail,"头尾"},
        {list->insert_tail,list->remove_head,"尾头"},
        {list->insert_tail,list->remove_tail,"尾尾"},
    };

    for(it2=0; it2<array_size(func_ptr); it2++){
        printf("\n测试第%d种方式,方式:%s:\n", it2+1, func_ptr[it2].msg);
        //必须进行初始化操作
        list->init(&list_head);
        //测试数据插入双向链表,采用2种方式之一
        for(it1=0; it1<array_size(md); it1++){
            md[it1].num = it1;
            func_ptr[it2].insert(&list_head, &md[it1].list_entry);
        }
        //测试数据脱离双向链表,采用2种方式之一
        while(!list->is_empty(&list_head)){
            //得到被移除的链表结点指针
            list_s* plist = func_ptr[it2].remove(&list_head);
            //通过链表结点指针得到包含该链表结构的结构体的指针
            my_data* pmd = list_data(plist, my_data, list_entry);
            //输出相关数据,验证正确性
            printf("md[0x%08X].num = %d\n", pmd, pmd->num);
        }
    }
    return 0;
}

测试数据输出:

测试第1种方式,方式:头头:
md[0x0012FF6C].num = 15
md[0x0012FF60].num = 14
md[0x0012FF54].num = 13
md[0x0012FF48].num = 12
md[0x0012FF3C].num = 11
md[0x0012FF30].num = 10
md[0x0012FF24].num = 9
md[0x0012FF18].num = 8
md[0x0012FF0C].num = 7
md[0x0012FF00].num = 6
md[0x0012FEF4].num = 5
md[0x0012FEE8].num = 4
md[0x0012FEDC].num = 3
md[0x0012FED0].num = 2
md[0x0012FEC4].num = 1
md[0x0012FEB8].num = 0

测试第2种方式,方式:头尾:
md[0x0012FEB8].num = 0
md[0x0012FEC4].num = 1
md[0x0012FED0].num = 2
md[0x0012FEDC].num = 3
md[0x0012FEE8].num = 4
md[0x0012FEF4].num = 5
md[0x0012FF00].num = 6
md[0x0012FF0C].num = 7
md[0x0012FF18].num = 8
md[0x0012FF24].num = 9
md[0x0012FF30].num = 10
md[0x0012FF3C].num = 11
md[0x0012FF48].num = 12
md[0x0012FF54].num = 13
md[0x0012FF60].num = 14
md[0x0012FF6C].num = 15

测试第3种方式,方式:尾头:
md[0x0012FEB8].num = 0
md[0x0012FEC4].num = 1
md[0x0012FED0].num = 2
md[0x0012FEDC].num = 3
md[0x0012FEE8].num = 4
md[0x0012FEF4].num = 5
md[0x0012FF00].num = 6
md[0x0012FF0C].num = 7
md[0x0012FF18].num = 8
md[0x0012FF24].num = 9
md[0x0012FF30].num = 10
md[0x0012FF3C].num = 11
md[0x0012FF48].num = 12
md[0x0012FF54].num = 13
md[0x0012FF60].num = 14
md[0x0012FF6C].num = 15

测试第4种方式,方式:尾尾:
md[0x0012FF6C].num = 15
md[0x0012FF60].num = 14
md[0x0012FF54].num = 13
md[0x0012FF48].num = 12
md[0x0012FF3C].num = 11
md[0x0012FF30].num = 10
md[0x0012FF24].num = 9
md[0x0012FF18].num = 8
md[0x0012FF0C].num = 7
md[0x0012FF00].num = 6
md[0x0012FEF4].num = 5
md[0x0012FEE8].num = 4
md[0x0012FEDC].num = 3
md[0x0012FED0].num = 2
md[0x0012FEC4].num = 1
md[0x0012FEB8].num = 0

源代码及BIN下载:https://files.cnblogs.com/nbsofer/list.7z
女孩不哭(QQ:191035066)@2013-02-25 13:27:55 http://www.cnblogs.com/nbsofer

posted @ 2013-02-25 13:31  女孩不哭  阅读(1980)  评论(0编辑  收藏  举报