LIST_ENTRY结构
2016-03-04 13:20
330 查看
在Windows驱动相关编程中,会用到该结构。Windows的源代码中大量使用了该结构。该结构用来组成常见的数据结构——双链表,并且带有头部节点。带头部节点的链表相对于不带头部节点的链表简化了一些链表操作,主要是插入和删除。
这是一个最简单的双链表节点,只保存了下一个节点指针
两者一对比,就让我们产生一个疑问,
这也是
这样,通过
头结点不带数据域,为
下面还有一个问题,我们通过
讲如何做之前,先看看Windows中怎么获取。就是使用
其中,
具体的实现原理比较简单,知道成员的地址,算结构体起始地址,只需要知道成员的偏移,因此,将结构体起始对齐到地址0,然后获取成员的地址,即为成员的偏移量,然后减去偏移量即可,该宏可如下实现:
LIST_ENTRY结构如下:
typedef struct _LIST_ENTRY { struct _LIST_ENTRY *Flink; struct _LIST_ENTRY *Blink; } LIST_ENTRY, *PLIST_ENTRY;
这是一个最简单的双链表节点,只保存了下一个节点指针
Flink(Follow Link)和前一个节点指针
Blink(Before Link)。我们自己使用链表时会在声明时加入数据域,同时指针域为我们自己的节点类型,例如:
typedef struct _NODE { int data; // 数据域 struct _NODE *Flink; // 后节点指针 struct _NODE *Blink; // 前节点指针 }NODE;
两者一对比,就让我们产生一个疑问,
LIST_ENTRY如何加入数据域?
这也是
LIST_ENTRY设计的巧妙处所在。
LIST_ENTRY结构不单独使用,而是在声明其它结构时,将其作为要组成双链表的结构体的一个成员。例如:
typedef struct _NODE { int data1; // 数据域1 LIST_ENTRY ListEntry; int data2; // 数据域2 }NODE;
这样,通过
ListEntry成员可以将结构体连接为一个双链表,如下图所示:
头结点不带数据域,为
LIST_ENTRY结构,使用前要用
InitializeListHead函数初始化。
下面还有一个问题,我们通过
LIST_ENTRY结构结构串联起来,使用时通过前后指针获取得到的都是
LIST_ENTRY结构本身,即
NODE结构中的成员
ListEntry。而实际使用时要得到的是
NODE结构本身的指针,这也就是招聘笔试面试过程中常常遇到的一个问题:知道结构体中某个成员的地址,如何获取结构体的起始地址?
讲如何做之前,先看看Windows中怎么获取。就是使用
CONTAINING_RECORD宏,这个宏的原型如下:
PCHAR CONTAINING_RECORD( [in] PCHAR Address, [in] TYPE Type, [in] PCHAR Field );
其中,
Type为结构体类型,
Field为
Type结构中的已知成员,
Address为
Field成员的已知地址,宏的结果为
Type结构的起始地址。对于我们的链表示例,获取链表第一个
NODE结构的起始地址用法为:
CONTAINING_RECORD(ListHead.Flink,NODE,ListEntry)
具体的实现原理比较简单,知道成员的地址,算结构体起始地址,只需要知道成员的偏移,因此,将结构体起始对齐到地址0,然后获取成员的地址,即为成员的偏移量,然后减去偏移量即可,该宏可如下实现:
((Type *)(((ULONG)Address) - (ULONG)(&(((Type *)0)->Field))))
相关文章推荐
- spring编码过滤器 配置
- c语言L->length与L.length
- 如何在CentOS 5/6上安装EPEL源(备忘)
- 输入和输出
- Android内存泄漏(3)
- [AndroidAnnotations框架]AndroidAnnotations的配置
- Linux启动或重启网卡【命令】
- 自我总结(1)
- ReactiveCocoa学习
- 常用hash算法及评测
- vim插件ctags的安装和使用
- Java 异常类型
- iOS UITabBarController底部tabbar的item间距设置
- android-USB-OTG 外部设备通讯 USB插拔检测
- HDOJ——1002 A+B Problem II
- linux sed 添加 删除 一行
- 怎样用好ZBrush中的PaintStop插件
- 关于dubbo的一些看法
- updata 网站的portfolio
- CentOS 7禁用IPV6 (备忘)