双向链表及链表头:

建立一个双向链表通常有一个独立的用于管理链表的链表头,链表头一般是不含有实体数据的,必须用INIT_LIST_HEAD()进行初始化,表头建立以后,就可以将带有数据结构的实体链表成员加入到链。

INIT_LIST_HEAD (&nphy_dev_list);

定义:

#define list_for_each_entry(pos, head, member)                \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))

它实际上是一个 for 循环,利用传入的 pos 作为循环变量,从表头 head 开始,逐项向后(next 方向)移动 pos,直至又回head.

我们将for循环分解为一下三点:

1. for循环初始化      pos = list_entry((head)->next, typeof(*pos), member);

2. for循环执行条件  &pos->member != (head);

3. 每循环一次执行   pos = list_entry(pos->member.next, typeof(*pos), member))

typeof()是取变量的类型,这里是取指针pos所指向数据的类型。

先看第一个:

#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define container_of(ptr, type, member) ({                      \
const typeof( ((type *))->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

讲讲container_of:作用:根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。

所以(type *)0)就是将0强转为一个地址,这个地址(0x0000)指向的是类型type的数据。当然,这里是一个技巧,并不是真的在地址0x0000存放了我们的数据。

((type *)0)->member的作用,这里的‘->’很显然是通过指针指取结构体成员的操作。指针就是刚才通过0强转的地址。所以也就是相当于地址0x0000 是结构体类型type的首地址,通过->’取其中的成员变量member。

typeof( ((type *)0)->member ) *__mptr = (ptr):知道member成员的类型,定义一个指针变量__mptr,指向的类型是member的类型,其初始化为ptr的值

offsetof(type,member):求出member在结构体中的偏移量

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

根据优先级的顺序,最里面的小括号优先级最高,TYPE *将整型常量0强制转换为TYPE型的指针,且这个指针指向的地址为0,也就是将地址0开始的一块存储空间映射为TYPE型的对象,接下来再对结构体中MEMBER成员进行取址,而整个TYPE结构体的首地址是0,这里获得的地址就是MEMBER成员在TYPE中的相对偏移量。再将这个偏移量强制转换成size_t型数据(无符号整型)。

(char *)__mptr - offsetof(type,member)就是__mptr - offset,即member类型的指针减去member在结构体中的偏移量。

小结:通过上面的分析,和定义出的注释,container_of的作用很明显了 -- 获得结构体的地址。那么我们需要给他提供三个参数,分别是:ptr:member成员的指针   type:结构体类型   member:成员member的名字。

这样我们就能通过container_of(ptr, type, member)的返回值,得到结构体的地址。

list_for_each_entry解析的更多相关文章

  1. 基于tiny4412的Linux内核移植 --- aliases节点解析

    作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...

  2. driver_register()函数解析

    driver_register()函数解析 /** * driver_register - register driver with bus * @drv: driver to register *  ...

  3. linux percpu机制解析【转】

    转自:http://blog.csdn.net/wh8_2011/article/details/53138377 一.概述 每cpu变量是最简单也是最重要的同步技术.每cpu变量主要是数据结构数组, ...

  4. Linux之进程的等待与其内核实现解析

    进程通过fork产生子进程,进程也会死亡,进程退出的时候将会进行内核清理,释放所有进程的资源,资源包括:内存资源,文件资源,信号量资源,共享内存资源,或者引用计数减一,或者彻底释放.     不过进程 ...

  5. 基于tiny4412的Linux内核移植 --- aliases节点解析【转】

    转自:https://www.cnblogs.com/pengdonglin137/p/5252348.html 阅读目录(Content) 作者信息 平台简介 正文 回到顶部(go to top) ...

  6. xenomai内核解析之信号signal(二)---xenomai信号处理机制

    xenomai信号 上篇文章讲了linux的信号在内核的发送与处理流程,现在加入了cobalt核,Cobalt内核为xenomai线程提供了信号机制.下面一一解析xenomai内核的信号处理机制. 1 ...

  7. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  8. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  9. Html Agility Pack 解析Html

    Hello 好久不见 哈哈,今天给大家分享一个解析Html的类库 Html Agility Pack.这个适用于想获取某网页里面的部分内容.今天就拿我的Csdn的博客列表来举例. 打开页面  用Fir ...

随机推荐

  1. 由于内部错误,服务器无法处理该请求。有关该错误的详细信息,请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 <serviceDebug> 配置行为)以便将异常信息发送回客户端,或打开对每个 Microsoft .NET Framework SDK 文档的跟踪并检查服务器跟踪日志。

    客户端调用WCF的时候报上面的错误,WCF只能序列化基础的数据类型,不能直接序列化SqlParameter类型,需要使用自定义类,然后在WCF服务端转换的方式解决: 自定义类代码如下: using S ...

  2. cs108 03 ( 调试, java通用性)

    Debuger Great questions These questions will solve most bugs: what method shows the symptom ? what l ...

  3. java调用kettle_导入jar包(1)

    版权声明:本文为博主原创文章,未经博主允许不得转载. Java调用Kettle执行任务或转换,需要使用Kettle中的jar,可以先导入lib目录中的几个基本的jar,如:kettle-core.ja ...

  4. JVM与外界通过数据通道进行数据交换

    使用I/O流访问file中的内容. JVM与外界通过数据通道进行数据交换. 分类: 按流分为输入流和输出流: 按传输单位分为字节流和字符流: 还可以分为节点流和过滤流. 节点流:负责数据源和程序之间建 ...

  5. 嵌入式开发之davinci--- ccs 编译lib库

    (1)ccs 简介 (2)ccs 输出格式coff elf (3)ccs 编译lib 算法库 (4)ccs 存在的问题 ---------------------------------------- ...

  6. ThinkPHP项目笔记之RBAC(权限)上篇

    当理清这5个表的关系,接下来,就是功能介绍了.

  7. jenkins发布docker到mesos

    1.前提是装好git.SSH.maven插件 2.jenkins新建一个项目,配好git拉取代码.maven编译构建(gradle构建也行,这不重要) 3.SSH Server,填写需要传输的jar文 ...

  8. 你真的搞懂ES6模块的导入导出规则了吗

    前言 模块作为ES6规范的核心部分之一,在实际项目开发中经常会看到它的身影,那么我们是否真正了解它的相关规则呢,今天就带大家一起了解一下模块的导入导出规则 导入 ES6模块的导入(即import)大致 ...

  9. ios开发之 -- 单例类

    单例模式是一种软件设计模式,再它的核心结构中指包含一个被称为单例类的特殊类. 通过单例模式可以保证系统中一个类只有一个势力而且该势力易于外界访问,从而方便对势力个数的控制并节约系统资源.如果希望在系统 ...

  10. Hadoop1.2.1 单机模式安装

    首先安装JDK: 然后安装hadoop: 最后的实例测试:首先在 /opt/data 目录下创建 input目录, 然后把hadoop的conf目录下的所有xml文件拷贝到上面的input目录, 然后 ...