• 对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

  • 相关阅读:
    各种数据库默认端口总结
    Entity Framework学习
    Entity Framework学习
    .Net MVC API初试
    MongoDB Shell
    MongoDB安装及简单实验
    Android Studio记录
    Android使用Fragment程序崩溃
    git操作笔记
    centos防火墙设置
  • 原文地址:https://www.cnblogs.com/memset/p/list_entry.html
Copyright © 2020-2023  润新知