linux内核的数据结构:1 双向循环链表

来源:互联网 发布:淘宝集市怎么进入 编辑:程序博客网 时间:2024/06/04 18:56

链表节点的定义在<include\linux\Types.h>中,如下:



list_head中只包含前后指针,而不包含节点具体的值。这样的设计使其更加通用,在使用的时候,我们在只需要在具体的结构体中包含list_head的一个节点即可。举一个小例子如下:

struct MyNode{    int val;     struct list_head entry;}
linux提供了链表的很多操作的实现,比如基本的增删查改,遍历等等。具体的实现在<include\linux\List.h>中,大多数实现比较简单,这里就不解释了。

由于list_head中没有保存我们需要的值,那么如何从一个list_head对象获得我们需要的节点的值就成了一个问题?使用上面的例子,我们找到了entry的地址,那么如果获得val的值呢?list_entry的宏帮我们实现了这个功能。


我们可以这样获得val的值:

int getVal(struct list_head* p){    struct MyNode* node = list_entry(p,struct MyNode, entry);    return node->val;}

list_entry如何实现的呢?

这里有几个地方需要解释一下:

  1. &(((TYPE*)0)->MEMBER):0虽然是一个非法地址,但是我们并没有对这个地址的内容进行过读的操作,所以这里并不会报错;这段代码假设从0地址开始出放置了一个TYPE结构,然后我们取出这个不存在的TYPE结构的MEMBER域的地址“addr”,由于结构体其实地址为0,那么“addr”就等于MEMBER相对于结构体起始位置的偏移量。注意,结构体的布局是从低地址开始的。
  2. typeof是gcc提供的扩展,返回值是该对象的类型。内核中更多的扩展语法参见

    Linux 内核中的 GCC 特性

  3. 定义__mptr的作用,我个人认为通过定义一个临时变量,会让编译器强制去检查type->member是否合法,这也在一定程度上弥补了宏本身没有类型检查的缺陷。

原创粉丝点击