比较

  • 共同点
    1.list_for_each和list_for_each_entry都是遍历链表的两个宏,本质上都是for循环。
    2.他们做的事情本质上都一样,A.获取链表头,B.判断链表项是不是链表头,C.指向链表的下一项。
    3.他们的区别:list_for_each遍历的链表,其链表项不属于某个结构体。或者说不关心它是不是包含在某个结构体中。
  • 区别
    1.list_for_each_entry遍历的链表,其每一项都是某个结构体中的成员,单纯遍历链表还不行,还要找到包含这个链表项的结构体的地址,从而为下一步应用该结构体做好准备,遍历的每一项为一个结构体。
    2.相比于list_for_each_entry,list_for_each_entry_safe用指针n对链表的对下一个数据结构进行了临时存储,所以如果在遍历链表的时候可能要删除链表的当前项,用list_for_each_entry_safe可以安全的删除,而不会影响接下来的遍历过程。

1 list_for_each

list_for_each内核中的定义:
/*** list_for_each - iterate over a list* @pos: the &struct list_head to use as a loop cursor.* @head: the head for your list.*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)

一个简单的for循环。

循环的初始化工作:pos指向链表头的下一项。

循环的条件:pos不是链表头。

每次循环要做的事情:pos指向链表中的下一项

2 关于list_for_each_entry相关函数

2.1 offsetof宏

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

该宏先将0转换成TYPE型指针,即形成一个指向地址0的TYPE指针,然后对TYPE中的MEMBER成员进行取址,而整个TYPE结构体的起始地址是0,那么这里取得的MEMBER的地址实际上等同于在TYPE中的相对偏移量。

2.2 container_of

/**
* 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被预定义成一个函数,它首先通过((type *)0)->member定义member类型的指针__mptr,这个指针指向ptr,获取到了我们所要求的结构体所包含的member的地址,然后(char *)__mptr - offsetof(type, member),通过member成员的地址减去它在结构体中的偏移量,然后强制转换成type指针就得到了这个结构体的地址,define预定义返回最后一句表达式的值,将所求结构体指针返回。
  总结一下,container_of的功能就是通过一个指向结构体成员member的指针,求得指向整个结构体的指针。

2.3 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的一个别名而已,完全等同

2.4 list_for_each_entry

/**
* list_for_each_entry     -     iterate over list of given type
* @pos:      the type * to use as a loop cursor.
* 这里要传入结构体指针,因为pos = list_entry((head)->next, typeof(*pos), member),list_entry返回的是结构
* 体指针, typeof(*pos) 是结构体的类型
* @head:     the head for your list.
* head是传入的是struct list_head 类型的指针,一般是LIST_HEAD过的只有pre和next的头,因为要作为遍历,head-*>next就是指向member的
* @member:   the name of the list_struct within the struct.
* member一般是pos结构体里面的list_header类型的成员
*/
#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))

这里强调一下双向链表及链表头的概念,建立一个双向链表通常有一个独立的用于管理链表的链表头,链表头一般不包含实体数据的,必须使用INIT_LIST_HEAD()进行初始化,表头建立后,就可以将带有数据结构的实体链表成员加入到链表张。关系如图所示。


list_for_each_entry被预定义为一个for循环语句,for循环的第一句获取(head)->next指向的member成员的结构体指针,将pos初始化为链表中除链表头之外的第一个实体链表成员,for的第三句通过pos->member.next指针遍历整个实体链表,当pos->member.next再次指向链表头的时候,说明已经遍历完毕,退出循环。

3 list_for_each_entry_safe

/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos:     the type * to use as a loop cursor.
* @n:       another type * to use as temporary storage
* @head:    the head for your list.
* @member:  the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member)               \for (pos = list_entry((head)->next, typeof(*pos), member),     \n = list_entry(pos->member.next, typeof(*pos), member);     \&pos->member != (head);                         \pos = n, n = list_entry(n->member.next, typeof(*n), member))

相比于list_for_each_entry,list_for_each_entry_safe用指针n对链表的对下一个数据结构进行了临时存储,所以如果在遍历链表的时候可能要删除链表的当前项,用list_for_each_entry_safe可以安全的删除,而不会影响接下来的遍历过程。

list_for_each,list_for_each_entry和list_for_each_entry_safe相关推荐

  1. linux 内核链表遍历宏 list_for_each_entry list_for_each_entry_safe

    看内核代码都会发现,内核链表的操作常用的二个宏list_for_each_entry和list_for_each_entry_safe 循序渐进,先从最底层的函数container_of 函数说起,其 ...

  2. linux内核中的数据结构

    http://vinllen.com/linuxnei-he-zhong-de-shu-ju-jie-gou/ https://zhuanlan.zhihu.com/p/58087261 https: ...

  3. 详解Linux内核之双向循环链表 By邪恶八进制

    [转载]详解Linux内核之双向循环链表 详解Linux内核之双向循环链表 信息来源:邪恶八进制信息安全团队(www.eviloctal.com) 摘要:      本文详解了内核中面向对象的list ...

  4. Linux内核常用数据结构

    Linux中最重要最常用如下四种: LIST:链表 <linux/list.h> Linux内核的标准链表就是采用"环形.双向"链表形式实现 沿着链表移动智能是线性移动 ...

  5. 安全函数不安全-多线程慎用List.h

    linux 开发应该多少都听过大名鼎鼎的 list.h ,其简洁优雅的设计,一个头文件完成了一个高可用的链表. 前言 linux 开发应该多少都听过大名鼎鼎的 list.h ,其简洁优雅的设计,一个头 ...

  6. linux 内核 链表 list_head 使用方法

    做内核驱动开发经常会使用linux内核最经典的双向链表 list_head, 以及它的拓展接口(或者宏定义): list_add , list_add_tail, list_del , list_en ...

  7. Linux 内核中的数据结构:双链表,基数树,位图

    Linux 内核中的数据结构 rtoax 2021年3月 1. 双向链表 Linux 内核自己实现了双向链表,可以在 include/linux/list.h 找到定义.我们将会从双向链表数据结构开始 ...

  8. Linux内核之数据双链表

    导读 Linux 内核中自己实现了双向链表,可以在 include/linux/list.h 找到定义.我们将会首先从双向链表数据结构开始介绍内核里的数据结构.为什么?因为它在内核里使用的很广泛,你只 ...

  9. Android MTK Flashlight学习

    MTK FLASHLIGHT学习 内核中常见的创建文件方法 文件权限定义 S_IRUSR等 强大的DEVICE_ARRT宏 DEVICE_ATTR和DEVICE_CREATE_FILE使用 内核中常见 ...

最新文章

  1. Office中如何实现公式颜色的更改?
  2. windows form (窗体) 之间传值
  3. Java 消息机制之回调详解
  4. 网络管理的任务包括linux,网络管理员的任务是阻止的10.152.8.0/21 一个基于Linux的防火墙的网络子网的默认端口上的所有出站SSH 连接。以下哪项规则集将完成这项任务?(单选题)...
  5. centos7 安装java和tomcat9
  6. Pinyin Comparison 拼音辨别 V1.2
  7. mysql两表查询单个_对两个表进行单个MySQL选择查询是可能的吗?
  8. PIX525-IPSEC-×××配置
  9. 【题解】Luogu P2157 [SDOI2009]学校食堂
  10. work-conserving scheduling 是什么
  11. 云网融合个人学习--云网融合典型场景分析【摘抄】
  12. linux接口vlan tag,linux c vlan tag 技术详解
  13. 使用libjpeg-turboYUV转JPG
  14. itpt_TCPL 第二章:类型、运算符以及表达式
  15. 移动支付之支付宝支付
  16. H3C服务器带外默认账号和密码
  17. MapReduce教程(01)- 初识MapReduce
  18. 截图神器FastStone Capture :小而强悍的截图一哥 (软件-神器系列第1篇)
  19. 机器人NAO:为自闭症儿童散去阴霾
  20. lscpu与cat /proc/cpuinfo获取的CPU信息释义

热门文章

  1. Kylin框架基本介绍
  2. 怎么看主机是否支持4k?
  3. 三种快速转换PDF为TXT的方法:简单、高效、免费
  4. 安卓 魅族PRO5 安装 Xposed框架
  5. php校园学校教室排课系统 php毕业设计题目课题选题 php毕业设计项目作品源码(1)功能概要
  6. 初学vue 在做项目时遇到的问题与解决办法(使用element组件)(二)
  7. 企业通过劳务派遣公司进行转移派遣的作用有哪些?
  8. 百度地图城市代码 大全,可在页面 ctrl+F 快速查找
  9. 《越狱》十大经典台词
  10. Dell服务器 iDRAC(IPMI) 连接管理服务器