在linux kernel里面链表应用非常广泛。

我们在应用程序中,定义一个链表结构通常要包含数据域,如下:

typedef struct _listNode{

int data;

struct _listNode *prev, *next;

}ListNode;

但在内核代码中,定义的链表都没有数据域, 如下:

struct list_head {

  struct list_head *next, *prev;

};
如果需要定义双链表结构,则在数据结构中包含一个list_head的成员变量,

struct book{

int data;

struct list_head list;

}

假设我们有另外一个结构体person,里面也有一个链表,这个链表是book的双链表。(代表一个人有多本书)

struct person{

char *name;

int booknum;

struct list_head booklist;

}

我们在初始化时,创建book的结构,并且将book加入到person的book list中。

struct person *myperson;

book= kmalloc(sizeof(struct book), GFP_KERNEL);

list_add_tail(&book->list, &myperson->booklist);
person->booknum++

那么后续我们知道booklist结构的地址(address A),如何知道booklist中的book结构(address B)呢?

struct book mybook;

list_for_each_entry(mybook, &myperson->booklist, list) //遍历myperson->booklist,每个元素放在mybook.

#define list_for_each_entry(pos, head, member) \
  for (pos = list_first_entry(head, typeof(*pos), member); \
  &pos->member != (head); \
  pos = list_next_entry(pos, member))

#define list_first_entry(ptr, type, member) \
  list_entry((ptr)->next, type, member)

最终展开的myperson->booklist的第一个元素的book结构为list_entry((&myperson->booklist)->next, struct book, list)

可以看出通过list_entry来获取myperson->booklist中的book结构。

#define list_entry(ptr, type, member) \
  container_of(ptr, type, member)

#define container_of(ptr, type, member) ({ \//ptr为(&myperson->booklist)的元素的地址(address A),type为实际的结构struct book,list是book中的list成员名字
  const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  (type *)( (char *)__mptr - offsetof(type,member) );})

将list_entry展开

((struct book*)((char *)((&myperson->booklist)->next)-(size_t)(&((struct book *)0)->list)))

(unsigned long)(&((struct book *)0)->list))即list相对于book 首地址的偏移(上图的offset)。

1. ( (type*)0 ) 将零转型为type类型指针; 
2. ((tpye*)0)->member访问结构中的数据成员; 
3. &( ( (type*)0 )->member)取出数据成员的地址; 
4.(size_t)(&(((type*)0)->member))转换成size_t类型,即member相对type结构首地址的偏移。

myperson的booklist 的地址(address A) 减去 偏移(offset)即为book结构首地址(Address B)。

Linux list_head的更多相关文章

  1. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  2. linux 内核分析之list_head

    转自:http://www.cnblogs.com/riky/archive/2006/12/28/606242.html 一.链表数据结构简介 链表是一种常用的组织有序数据的数据结构,它通过指针将一 ...

  3. linux内核的双链表list_head、散列表hlist_head

    一.双链表list_head 1.基本概念 linux内核提供的标准链表可用于将任何类型的数据结构彼此链接起来. 不是数据内嵌到链表中,而是把链表内嵌到数据对象中. 即:加入链表的数据结构必须包含一个 ...

  4. Linux 内核list_head 学习

    Linux 内核list_head 学习(一) http://www.cnblogs.com/zhuyp1015/archive/2012/06/02/2532240.html 在Linux内核中,提 ...

  5. Linux利用list_head结构实现双向链表

    原文地址:http://www.cnblogs.com/bastard/archive/2012/10/19/2731107.html 通常实现双向链表的数据结构: struct list_node1 ...

  6. [转载]Linux内核list_head学习(二)

    前一篇文章讨论了list_head 结构的基本结构和实现原理,本文主要介绍一下实例代码. 自己如果想在应用程序中使用list_head 的相应操作(当然应该没人使用了,C++ STL提供了list 用 ...

  7. [转载]Linux 内核list_head 学习(一)

    在Linux内核中,提供了一个用来创建双向循环链表的结构 list_head.虽然linux内核是用C语言写的,但是list_head的引入,使得内核数据结构也可以拥有面向对象的特性,通过使用操作li ...

  8. Linux内核中的双向链表struct list_head

    一.双向链表list_head Linux内核驱动开发会经常用到Linux内核中经典的双向链表list_head,以及它的拓展接口和宏定义:list_add.list_add_tail.list_de ...

  9. go例子(一) 使用go语言实现linux内核中的list_head

    package list 代码 package list import ( "fmt" ) // 数据接口 type ElemType interface{} // 节点 type ...

随机推荐

  1. 在myEclipse中根据图表自动生成Hibernate文件

    1.新建一个Java Project项目,在scr中创建两个包:Com.hibernate.po 和com.hibernate.dao 2. 3.点击ok 4. 5.选中MyElipse Derby, ...

  2. 题解 P5613 【[MtOI2019]黑蚊子多】

    题目传送门 一道模拟题目,签到送分题. 您需要的知识 1.while循环 2.for循环 3.一维数组 思路: Step 1:按题目要求,定义a[],n,m,k int a[10001]; int n ...

  3. Linux C++ 直接选择排序,冒泡排序,快速排序

    选择排序的思想是:每次从待排序中选择最小(大)的元素插入已经排好的序列中. /*直接选择排序*/ #include <iostream> using namespace std; void ...

  4. SMTS Silicon Design Engineer Location: Beijing, Beijing, CN

    https://jobs.amd.com/job/Beijing-Physical-Design-Engineer-Beij/603603700/?locale=en_US What you do a ...

  5. AngularJS中transclude用法详解

    这篇文章主要介绍了AngularJS中transclude用法,详细分析了transclude的具体功能.使用技巧与相关注意事项,需要的朋友可以参考下 本文实例讲述了AngularJS中transcl ...

  6. Hog实例

    1.计算Hog的特征得维度: #include <iostream> #include <opencv2/core/core.hpp> #include <opencv2 ...

  7. python 深浅copy总结

    总结: ''' 总结:假设l1为原数据,l2为deepcopy后的数据: 1.浅copy,只能改变第一层的内存地址(不可变数据类型除外). 2.深copy,能够改变第一层和第二层的内存地址(不可变数据 ...

  8. 巨杉Tech | 使用 SequoiaDB + Docker + Nodejs 搭建 Web 服务器

    容器化技术的出现大大简化了应用开发人员在构建底层基础设施的工作.SequoiaDB 巨杉数据库于3.2.1版本正式推出了 Docker 容器化部署方案,本文将会基于 SequoiaDB 巨杉数据库与N ...

  9. 一点点学习PS--实战一

    1.安装ps cc 2017,软件包获取:关注公众号软件管家 2.ps常用快捷键 ALT+J 复制图层 CTRL+T 旋转(右键点击可垂直翻转,画倒影常用) CTRL+M  曲线,提亮图片颜色 CTR ...

  10. linq和匿名方法、委托、匿名委托、lambda

    委托相当于JavaScript中的闭包,c++中的函数指针. c#为了引进这个函数指针,将其进行包装成“委托”,同时将非托管的变成托管的. 1.最初的委托该怎么用 弊端:写的代码量过多,还要写一个显示 ...