内核里面用list_for_each_entry实在太多了,定义在linux-3.10/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_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,linux-3.10/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 *))->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

宏定义的第一行:typeof(x)是gcc预处理,获取x的类型,这里((type *)0)->member利用p=0的指针指向相应结构体(type)的成员,typeof获取该成员的类型并定义__mptr。

第二行:#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER),跟第一行的((type *)0)->member一个样子,获取结构体(type)的偏移量,最后__mptr转换成(char *)减去自己在结构体(type)的偏移量得到结构体(type)的指针。

可以看出第一行在功能上是没有什么卵用,其实只是作为类型检测,实现一个给定成员类型(member)的指针(ptr)找到这个成员的结构体(type)功能的只在第二行。

返回看list_entry(ptr, type, member)其实就是通过ptr找到type。

再回到list_for_each_entry(pos, head, member)的实现可以知道,用list_head通过list_entry找到包含next list_head的结构体(pos)作为变量进行循环。可得要使用list_for_each_entry,struct pos里面的成员必须包含list_head。所以在linux里面的struct经常看到list_head这个成员就是这个道理

最新文章

  1. AndroidStudio关联svn并上传代码到svn服务器上
  2. 摄像头/光驱故障:由于其配置信息(注册表中的)不完整或已损坏,Windows 无法启动这个硬件设备。 (代码 19)
  3. 在MVC3中修改KindEditor实现图片删除
  4. Http协议之Get和Post的区别
  5. Cheatsheet: 2014 04.01 ~ 04.30
  6. SQL SERVER(MSSQLSERVER) 服务无法启用 特定服务错误:126
  7. SDKInitializer.initialize报错求助
  8. delphi 反射(原理)
  9. Bluetooth LE(低功耗蓝牙) - 第一部分
  10. win7 安装 redis +php扩展
  11. 远程方法调用(RMI)原理与示例 (转)
  12. 2.定义图形类Shape,该类中有获得面积的方法getArea();定义长方形类Rect,该类是Shape的子类,类中有矩形长和宽的变量double a,double b,设置长和宽的方法setWidth()、setHeight(),使用getArea()求矩形面积;利用getArea方法实现题1中圆面积的求解。
  13. Thuwc 2019 & wc 2019 划水记
  14. SpringMVC的执行流程
  15. Docker中如何删除image(镜像)
  16. Confluence 6 缓存性能优化
  17. 701 C. They Are Everywhere
  18. python3 线程池-threadpool模块与concurrent.futures模块
  19. 盒子变形-盒子加padding后 变形问题,
  20. java学习第03天(运算符、语句)

热门文章

  1. yii框架模型操作
  2. 【转载】openwrt框架分析
  3. Shell编程基础及变量
  4. DNS 缓存机制原理
  5. POJ 1144 无向图求割点
  6. redis中文文档
  7. MYSQL limit用法
  8. Email-Ext Plugin install ------ Jenkins Plugins
  9. Caused by: org.apache.ibatis.binding.BindingException: Parameter 'parameter' not found.解决
  10. 字符在内存中最终的表示形式是什么?是某种字符编码还是码位(Code Point)?