对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