LIST_ENTRY链表学习
来源:互联网 发布:js模块化编程原理 编辑:程序博客网 时间:2024/04/27 22:37
链表是驱动开发中经常遇到的一个数据结构,主要是双向循环链表;要使用链表,需要用到一个LIST_ENTRY的结构,其定义如下:
typedef struct _LIST_ENTRY { struct _LIST_ENTRY *Flink; // 指向下一个节点 struct _LIST_ENTRY *Blink; // 指向前一个节点} LIST_ENTRY, *PLIST_ENTRY;
每个双向链表都是一个以链表头作为链表第一个元素,初次使用时需要进行初始化,主要讲链表头的Flink,Blink指向自己,连表头所代表的是空链。初始化时用InitializeListHead宏实现。
常用操作:
InitializeListHead,初始化链表头 IsListEmpty,判断链表是否为空 InsertHeadList,从链表头部插入节点 InsertTailList,从链表尾部插入节点 RemoveHeadList,从链表头部删除节点 RemoveTailList,从链表尾部删除节点 CONTAINING_RECORD,从RemoveHeadList或者RemoveTailList返回的数据获取一个指向删除节点的指针实例代码(from windows 驱动开发技术详解)
#include <ntddk.h>typedef struct _MYDATASTRUCT {ULONG number;LIST_ENTRY ListEntry;}MYDATASTRUCT, *PMYDATASTRUCT;VOID LinkListTest(){LIST_ENTRY linkListHead;//初始化链表InitializeListHead(&linkListHead);PMYDATASTRUCT pData;ULONG i = 0;//在链表中插入10个元素KdPrint(("Begin insert to link list\n"));for(i=0; i<10; i++){//分配页内存pData = (PMYDATASTRUCT)ExAllocatePool(PagedPool, sizeof(MYDATASTRUCT));pData->number = i;//从头部插入链表InsertHeadList(&linkListHead, &pData->ListEntry);}//从链表中取出,并显示KdPrint(("Begin remove from link list\n"));while(!IsListEmpty(&linkListHead)){//从尾部删除一个元素PLIST_ENTRY pEntry = RemoveTailList(&linkListHead); //返回删除结构中ListEntry的位置pData = CONTAINING_RECORD(pEntry,MYDATASTRUCT,ListEntry);KdPrint(("%d \n",pData->number));ExFreePool(pData);}}VOID DriverUnload(PDRIVER_OBJECT pDriverObject){KdPrint(("Enter DriverUnload...\n"));}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath) {KdPrint(("Enter DriverEntry\n"));pDriverObject->DriverUnload = DriverUnload;LinkListTest();KdPrint(("Exit DriverEntry\n"));return STATUS_SUCCESS;}
下面用windbg跟了下看看:
在InitializeListHead函数之前,查看 linkListHead
kd> dt linkListHeadLocal var @ 0xf78eec78 Type _LIST_ENTRY [ 0x8 - 0x386 ] +0x000 Flink : 0x00000008 _LIST_ENTRY +0x004 Blink : 0x00000386 _LIST_ENTRY
可知Flink、Blink随机给了两个值
InitializeListHead函数执行后
kd> dt linkListHeadLocal var @ 0xf78eec78 Type _LIST_ENTRY [ 0xf78eec78 - 0xf78eec78 ] +0x000 Flink : 0xf78eec78 _LIST_ENTRY [ 0xf78eec78 - 0xf78eec78 ] +0x004 Blink : 0xf78eec78 _LIST_ENTRY [ 0xf78eec78 - 0xf78eec78 ]
可知结构中两个成员都指向自己。
跟踪程序,当程序中链表有两个元素后(除了表头),查看下链表情况
链头:
kd> dt linkListHeadLocal var @ 0xf78eec78 Type _LIST_ENTRY [ 0xe139a29c - 0xe12a9ba4 ] +0x000 Flink : 0xe139a29c _LIST_ENTRY [ 0xe12a9ba4 - 0xf78eec78 ] +0x004 Blink : 0xe12a9ba4 _LIST_ENTRY [ 0xf78eec78 - 0xe139a29c ]
第一个元素:
前三个值分别对应结构
typedef struct _MYDATASTRUCT {ULONG number;LIST_ENTRY ListEntry;}MYDATASTRUCT, *PMYDATASTRUCT;
的
{ ULONG number; _LIST_ENTRY *Flink; _LIST_ENTRY *Blink;}
值
kd> dd 0xe139a29c -4e139a298 00000001 e12a9ba4 f78eec78 87357020e139a2a8 0c090203 76666647 e139a2b8 00000000e139a2b8 647ce000 01c2f458 00000000 007d0000e139a2c8 00001630 e1d1c308 00000001 00000000
第二个元素:
kd> dd 0xe12a9ba4-4e12a9ba0 00000000 f78eec78 e139a29c 87c816f0e12a9bb0 0c060403 f7564d43 e115c740 e12aac40e12a9bc0 e12a9bc0 e12a9bc0 0009c000 00004000e12a9bd0 dea5c000 884d1831 00000000 05000072
因为是从头部插入链表,所以先插入的元素在链表后面。
1 1
- LIST_ENTRY链表学习
- windows驱动开发学习笔记一双向链表LIST_ENTRY
- container_of()和内核链表中的list_entry()
- 深入分析 Linux 内核链表 list_entry...
- 深入分析 Linux 内核链表 list_entry...
- 内核链表list_entry()宏详解
- container_of()和内核链表中的list_entry()
- LIST_ENTRY双向链表的练习
- linux内核学习(17)内核编程基本功之内核链表list_entry
- linux内核学习(17)内核编程基本功之内核链表list_entry
- list_head和list_entry学习
- list_entry
- list_entry
- list_entry
- list_entry
- list_entry
- LIST_ENTRY
- list_entry()
- JAVA编程思想(3) - 复用类(一)
- 对 Linux 新手非常有用的 20 个命令
- 庖丁解牛,彻底掌握c++类型转换
- 迅雷2014校园招聘笔试题
- Object类和它的方法
- LIST_ENTRY链表学习
- C# 属性
- 使用plsql导出oracle表的数据
- Draft
- LeetCode | Minimum Window Substring
- 利用包装类传json数据
- Eclipse maven插件 m2e安装
- 帝国cms 设置关键字替换次数 防止关键字替换到alt
- UVa10048_Audiophobia(最短路/floyd)(小白书图论专题)