LIST_ENTRY链表学习

 

 

链表是驱动开发中经常遇到的一个数据结构,主要是双向循环链表;要使用链表,需要用到一个LIST_ENTRY的结构,其定义如下:

 

 
  1.  
    typedef struct _LIST_ENTRY {
  2.  
    struct _LIST_ENTRY *Flink; // 指向下一个节点
  3.  
    struct _LIST_ENTRY *Blink; // 指向前一个节点
  4.  
    } LIST_ENTRY, *PLIST_ENTRY;
 

 

每个双向链表都是一个以链表头作为链表第一个元素,初次使用时需要进行初始化,主要讲链表头的Flink,Blink指向自己,连表头所代表的是空链。初始化时用InitializeListHead宏实现。

 

常用操作:

 

 
  1.  
    InitializeListHead,初始化链表头
  2.  
    IsListEmpty,判断链表是否为空
  3.  
    InsertHeadList,从链表头部插入节点
  4.  
    InsertTailList,从链表尾部插入节点
  5.  
    RemoveHeadList,从链表头部删除节点
  6.  
    RemoveTailList,从链表尾部删除节点
  7.  
    CONTAINING_RECORD,从RemoveHeadList或者RemoveTailList返回的数据获取一个指向删除节点的指针
 
实例代码(from windows 驱动开发技术详解)

 

 

 
  1.  
    #include <ntddk.h>
  2.  
     
  3.  
    typedef struct _MYDATASTRUCT
  4.  
    {
  5.  
    ULONG number;
  6.  
    LIST_ENTRY ListEntry;
  7.  
    }MYDATASTRUCT, *PMYDATASTRUCT;
  8.  
     
  9.  
    VOID LinkListTest()
  10.  
    {
  11.  
    LIST_ENTRY linkListHead;
  12.  
    //初始化链表
  13.  
    InitializeListHead(&linkListHead);
  14.  
    PMYDATASTRUCT pData;
  15.  
    ULONG i = 0;
  16.  
    //在链表中插入10个元素
  17.  
    KdPrint(("Begin insert to link list\n"));
  18.  
    for(i=0; i<10; i++)
  19.  
    {
  20.  
    //分配页内存
  21.  
    pData = (PMYDATASTRUCT)ExAllocatePool(PagedPool, sizeof(MYDATASTRUCT));
  22.  
    pData->number = i;
  23.  
    //从头部插入链表
  24.  
    InsertHeadList(&linkListHead, &pData->ListEntry);
  25.  
    }
  26.  
    //从链表中取出,并显示
  27.  
    KdPrint(("Begin remove from link list\n"));
  28.  
    while(!IsListEmpty(&linkListHead))
  29.  
    {
  30.  
    //从尾部删除一个元素
  31.  
    PLIST_ENTRY pEntry = RemoveTailList(&linkListHead); //返回删除结构中ListEntry的位置
  32.  
    pData = CONTAINING_RECORD(pEntry,
  33.  
    MYDATASTRUCT,
  34.  
    ListEntry);
  35.  
    KdPrint(("%d \n",pData->number));
  36.  
    ExFreePool(pData);
  37.  
    }
  38.  
    }
  39.  
     
  40.  
    VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
  41.  
    {
  42.  
    KdPrint(("Enter DriverUnload...\n"));
  43.  
    }
  44.  
     
  45.  
    NTSTATUS
  46.  
    DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath)
  47.  
    {
  48.  
    KdPrint(("Enter DriverEntry\n"));
  49.  
    pDriverObject->DriverUnload = DriverUnload;
  50.  
    LinkListTest();
  51.  
    KdPrint(("Exit DriverEntry\n"));
  52.  
    return STATUS_SUCCESS;
  53.  
    }
 

下面用windbg跟了下看看:

 

在InitializeListHead函数之前,查看 linkListHead

 

 
  1.  
    kd> dt linkListHead
  2.  
    Local var @ 0xf78eec78 Type _LIST_ENTRY
  3.  
    [ 0x8 - 0x386 ]
  4.  
    +0x000 Flink : 0x00000008 _LIST_ENTRY
  5.  
    +0x004 Blink : 0x00000386 _LIST_ENTRY
 

可知Flink、Blink随机给了两个值

 

InitializeListHead函数执行后

 

 
  1.  
    kd> dt linkListHead
  2.  
    Local var @ 0xf78eec78 Type _LIST_ENTRY
  3.  
    [ 0xf78eec78 - 0xf78eec78 ]
  4.  
    +0x000 Flink : 0xf78eec78 _LIST_ENTRY [ 0xf78eec78 - 0xf78eec78 ]
  5.  
    +0x004 Blink : 0xf78eec78 _LIST_ENTRY [ 0xf78eec78 - 0xf78eec78 ]
 

可知结构中两个成员都指向自己。

 

跟踪程序,当程序中链表有两个元素后(除了表头),查看下链表情况

链头:

 

 
  1.  
    kd> dt linkListHead
  2.  
    Local var @ 0xf78eec78 Type _LIST_ENTRY
  3.  
    [ 0xe139a29c - 0xe12a9ba4 ]
  4.  
    +0x000 Flink : 0xe139a29c _LIST_ENTRY [ 0xe12a9ba4 - 0xf78eec78 ]
  5.  
    +0x004 Blink : 0xe12a9ba4 _LIST_ENTRY [ 0xf78eec78 - 0xe139a29c ]
 
 

第一个元素:

前三个值分别对应结构

 

 
  1.  
    typedef struct _MYDATASTRUCT
  2.  
    {
  3.  
    ULONG number;
  4.  
    LIST_ENTRY ListEntry;
  5.  
    }MYDATASTRUCT, *PMYDATASTRUCT;
 

 

 
  1.  
    {
  2.  
    ULONG number;
  3.  
    _LIST_ENTRY *Flink;
  4.  
    _LIST_ENTRY *Blink;
  5.  
    }
 

 

 
  1.  
    kd> dd 0xe139a29c -4
  2.  
    e139a298 00000001 e12a9ba4 f78eec78 87357020
  3.  
    e139a2a8 0c090203 76666647 e139a2b8 00000000
  4.  
    e139a2b8 647ce000 01c2f458 00000000 007d0000
  5.  
    e139a2c8 00001630 e1d1c308 00000001 00000000
 

第二个元素:

 

 

 
  1.  
    kd> dd 0xe12a9ba4-4
  2.  
    e12a9ba0 00000000 f78eec78 e139a29c 87c816f0
  3.  
    e12a9bb0 0c060403 f7564d43 e115c740 e12aac40
  4.  
    e12a9bc0 e12a9bc0 e12a9bc0 0009c000 00004000
  5.  
    e12a9bd0 dea5c000 884d1831 00000000 05000072
 

 

因为是从头部插入链表,所以先插入的元素在链表后面。

 

转载地址https://blog.csdn.net/hjxyshell/article/details/38742117

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值