我是靠谱客的博主 缓慢香菇,最近开发中收集的这篇文章主要介绍list_for_each_entry宏函数解析(上)list_for_each_entry宏函数解析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

list_for_each_entry宏函数解析

欢迎转载,相互学习,但请注明出处,非常感谢!

list_for_each_entry宏函数解析(上)_人有三样东西是无法隐瞒的,咳嗽,穷困和爱,你想隐瞒越欲盖弥彰-CSDN博客

- 刘金辉

/***************************************/

     博文中源码来自Linux3.10.14

/***************************************/

1. list_for_each_entry 定义

在内核中,经常用到 list_for_each_entry 函数,严格上讲,这个是宏函数,来看看具体内容。

在文件include/linux/list.h 中可以找到其定义

/**
 * list_for_each_entry	-	iterate over list of given type
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#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))

上面定义了宏函数list_for_each_entry ,其中有一个我们非常熟悉的 for循环!!

我们将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))

所以我们先看看第一个,

pos = list_entry((head)->next, typeof(*pos), member);

这里值得我们注意的是pos。从for循环的结构上可以看出pos是控制for循环的一个变量,不是我们常用的int类型而是指针

 * @pos:	the type * to use as a loop cursor.

那么,在for循环开始前,pos = list_entry((head)->next, typeof(*pos), member) ,这里应该是对pos进行初始化。下面是list_entry的定义:

/**
 * list_entry - get the struct for this entry
 * @ptr:	the &struct list_head pointer.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_struct within the struct.
 */
#define list_entry(ptr, type, member) 
	container_of(ptr, type, member)

所以list_entry也是宏定义,定义为container_of,这也没什么难的,所以我们继续寻找container_of 的定义

在文件include/linux/kernel.h中有如下定义

/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:	the pointer to the member.
 * @type:	the type of the container struct this is embedded in.
 * @member:	the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({			
	const typeof( ((type *)0)->member ) *__mptr = (ptr);	
	(type *)( (char *)__mptr - offsetof(type,member) );})

到这里,就是非常重要的部分了,所以我们要详细分析一下:

2. container_of 详解

2.1(type *)0)->member  得到成员类型

我们可以发现指针是(type *)0),貌似有点怪怪的吧。其实这也是一个非常有技巧的操作,值得我们借鉴和学习。(type *)0是一个强转的操作,将0强行装换成type类型的指针。type类型是container_of的第二个参数,所以在使用container_of时第二个参数应该传类型吧,那么这里的调用是不是传的类型呢???

通过上面的分析pos = list_entry((head)->next, typeof(*pos), member)  , list_entry ---> container_of,因为list_entry第二个参数是typeof(* pos)typeof()是取变量的类型,这里是取指针pos所指向数据的类型,至于到底是什么类型,等下再分析。

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

注意:32bit系统 为0x0000, 64bit系统 为0x00000000,这里已32bit为例子。64bit同理

那么这样做的好处是什么?为什么要这么做? 

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

2.2 const typeof( ((type *)0)->member ) *__mptr = (ptr);   定义指针

知道(type *)0)->member的作用就是得到成员变量member后,再通过typeof((type *)0)->member),就知道member成员的类型了。

init * p;我们知道其意思定义一个int类型的指针。在一些比较通用的函数里面,需要定义一个指针,但是不巧的是不能确定指针的类型,所以在程序里面不能写死,那么该怎么办?这个时候就可以利用typeof帮我们搞定。

const typeof( ((type *)0)->member ) *__mptr = (ptr);就是利用这个技巧。其中typeof( ((type *)0)->member )就是member的类型,__mptr是变量。所以这句话是定义一个指针变量__mptr,指向的类型是member的类型,其初始化为ptr的值。ptr是container_of(ptr, type, member)的第一个参数。

2.3  根据偏移求结构体首地址

	(type *)( (char *)__mptr - offsetof(type,member) );})

这行代码相对比较简单了,__mptr是上面定义的member成员类型的指针,初始化为ptr。offsetof(type,member)是求出member在结构体中的偏移量,其中type是结构体的类型。(char *)__mptr - offsetof(type,member)就是__mptr - offset,即member类型的指针减去member在结构体中的偏移量。一般__mptr = ptr,ptr是member的地址,那么member的地址减去member在结构体中偏移量不就是得到结构体的地址了吗。为了更好的理解,可以参考下图:


/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:	the pointer to the member.
 * @type:	the type of the container struct this is embedded in.
 * @member:	the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({			
	const typeof( ((type *)0)->member ) *__mptr = (ptr);	
	(type *)( (char *)__mptr - offsetof(type,member) );})

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

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


 

最后

以上就是缓慢香菇为你收集整理的list_for_each_entry宏函数解析(上)list_for_each_entry宏函数解析的全部内容,希望文章能够帮你解决list_for_each_entry宏函数解析(上)list_for_each_entry宏函数解析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部