container_of和list_for_each_entry 及其相关函数的分析

list_for_each_entry_safe 简介 (head);=(head);=(head);=(head);=(head);for=(head);=(head);=(head);->=(head);=(head);=(head);=(head);=(head);->=(head);=(head);=(head);=(head);; 阅读详情

Linux代码看的比较多了,经常会遇到container_of和list_for_each_entry,特别是list_for_each_entry比较多,因为Linux经常用到链表,虽然知道这些函数的大概意思,但一旦出现一个类似的函数比如list_for_each_entry_safe就又会感到头大,所以下定决心分析总结一下这些函数的用法,以后再看到这些面孔的时候也会轻松很多,读Linux代码的时候不会那么吃力。

我们知道list_for_each_entry会用到list_entry,而list_entry用到container_of,所以首先讲讲container_of。

在讲container_of之前我们不得不提到offsetof,因为在container_of中会使用到它,所以我们看下来,把list_for_each_entry函数的用法理顺我们对整个Linux中经常用到的一些函数就会比较清楚了。

1. offsetof /**/ #define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER) 理解offsetof的关键在于&((TYPE*)0)->MEMBER,几乎可以说只要理解了这一部分,后面的几个函数都能够解决,那么我们看看这一部分究竟完成了怎样的工作。根据优先级的顺序,最里面的小括号优先级最高,TYPE *将整型常量0强制转换为TYPE型的指针,且这个指针指向的地址为0,也就是将地址0开始的一块存储空间映射为TYPE型的对象,接下来再对结构体中MEMBER成员进行取址,而整个TYPE结构体的首地址是0,这里获得的地址就是MEMBER成员在TYPE中的相对偏移量。再将这个偏移量强制转换成size_t型数据(无符号整型)。 所以整个offsetof的功能就是获取MEMBER成员在TYPE型数据中的偏移量。接下来我们可以讲一下container_of了。

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的地址,接下来我们用这个地址减去成员member在结构体中的相对偏移量,就可以获取到所求结构体的地址, (char *)__mptr - offsetof(type,member)就实现了这个过程,最后再把这个地址强制转换成type型指针,就获取到了所求结构体指针,define预定义返回最后一句话的值,将所求结构体指针返回。所以整个container_of的功能就是通过指向结构体成员member的指针ptr获取指向整个结构体的指针。container_of清楚了,那list_entry就更是一目了然了。

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。接下来分析我们最终想要知道的list_for_each_entry的实现过程。

4. list_for_each_entry /**
* 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的基础上分析list_for_each_entry本来是一件比较轻松的事情,但在这里还是要强调一下双向链表及链表头的概念,否则对list_for_each_entry的理解还是一知半解。建立一个双向链表通常有一个独立的用于管理链表的链表头,链表头一般是不含有实体数据的,必须用INIT_LIST_HEAD()进行初始化,表头建立以后,就可以将带有数据结构的实体链表成员加入到链表中,链表头和链表的关系如图所示:链表头和链表的关系清楚了,我们才能完全理解list_for_each_entry。list_for_each_entry被预定义成一个for循环语句,for循环的第一句话获取(head)->next指向的member成员的数据结构指针,也就是将pos初始化为除链表头之外的第一个实体链表成员,for的第三句话通过pos->member.next指针遍历整个实体链表,当pos->member.next再次指向我们的链表头的时候跳出for循环。整个过程没有对链表头进行遍历(不需要被遍历),所以使用list_for_each_entry遍历链表必须从链表头开始。 因此可以看出,list_for_each_entry的功能就是遍历以head为链表头的实体链表,对实体链表中的数据结构进行处理。

5. list_for_each_entry_safe /**
* list_for_each_entry_safe - iterate over list of given type safe againstremoval 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可以安全的删除,而不会影响接下来的遍历过程(用n指针可以继续完成接下来的遍历, 而list_for_each_entry则无法继续遍历)。

 

Linux内核list&hlist;解读 目录 1. 前言 2 2. 通用宏 2 2.1. typeof 2 2.1.1. 定义 3 2.1.2. 用途 3 2.1.3. 示例 3 2.2. offset_of 3 2.2.1. 定义 3 2.2.2. 作用 3 2.2.3. 原理 3 2.2.4. 示例 3 2.3. container_of 4 2.3.1. 定义 4 2.3.2. 作用 4 2.3.3. 示例 4 2.4. prefetch 4 2.4.1. 定义 4 2.4.2. 作用 4 3. list 5 3.1. list结构 5 3.1.1. 定义 5 3.1.2. 作用 5 3.1.3. 解读 5 3.1.4. 示例 5 3.2. 遍历方向 6 3.3. list_entry 6 3.3.1. 定义 6 3.3.2. 作用 7 3.4. list_for_each 7 3.4.1. 定义 7 3.4.2. 作用 7 3.4.3. 示例 7 3.5. __list_for_each 8 3.5.1. 定义 8 3.5.2. 作用 8 3.6. list_for_each_prev 8 3.6.1. 定义 8 3.6.2. 作用 8 3.7. list_for_each_safe 8 3.7.1. 定义 8 3.7.2. 作用 9 3.7.3. 区别 9 3.7.4. 示例 9 3.8. list_for_each_entry 9 3.8.1. 定义 9 3.8.2. 作用 10 3.8.3. 区别 10 3.8.4. 完整示例 10 3.9. list_for_each_entry_safe 12 3.9.1. 定义 12 3.9.2. 作用 13 3.10. list_for_each_entry_reverse 13 3.10.1. 定义 13 3.10.2. 作用 13 3.11. list_for_each_entry_continue 13 3.11.1. 定义 13 3.11.2. 作用 13 3.11.3. 区别 13 3.12. list_for_each_safe_rcu 14 4. hlist(hash list) 14 4.1. hlist(hash list)结构 14 4.1.1. 简述 14 4.1.2. 定义 14 立即下载

相关推荐

【算法】基于STM32的MPU6050卡尔曼滤波算法(入门级)

1. 简介 卡尔曼滤波(Kalman filtering)是一种利用线性系统状态方程,通过系统输入输出观测数据,对系统状态进行最优估计的算法。由于观测数据中包括系统中的噪声和干扰的影响,所以最优估计也可看作是滤波过程。详情见:卡尔曼滤波简介 MPU6050的解算主要有三种姿态融合算法:四元数法 、一阶互补算法和卡尔曼滤波算法。我们常用的DMP库使用的是四元数法,本文采用卡尔曼滤波算法,使用RT-Thread国产操作系统,利用env工具进行串口、模拟IIC环境配置,使用10ms的线程进行卡尔曼滤波解算。 2.

weixin_44549777的博客 3万+

【Linux内核】内核常用链表宏解释

这段代码是一个宏定义,用于遍历一个链表中所有的元素,并且在遍历过程中可以安全地删除元素。具体来说,这个宏定义的功能是:遍历链表中所有的元素,从头节点开始,直到尾节点结束。对于每个元素,使用给定的结构体成员变量名找到它所属的结构体对象,并且将该对象的指针赋值给给定的变量名。在遍历过程中,可以安全地删除当前元素,因为它在删除前会先保存下一个元素的指针,保证不会影响遍历的正确性。

逆风水手的博客 4002

重访时间与覆盖分析的stk操作

1.打开stk 2.创建一个新的场景,命名为Test,选择地球为场景星球,若为金星,可在Central Body里选择Venus(金星自转周期慢,自转周期243天,卫星轨道变化不明显)(其中start stop时间可设置长一些) 3.插入一个AreaTarget或者place,以AreaTarget为例 选择Pattern,Add三个点(用法可见前面的博客,有时候编程的代码也可以帮助理解stk的操作) 4.插入Satellite,选择Orbit Wizard(若想设置卫星的六根数也可

weixin_42664107的博客 1万+

linux的内存分配和 list_for_each_entry_safe()函数的介绍

碎碎念 这些内容主要是我翻译国外师傅博客的一小部分内容得来的。不得不说,这个师傅写的文章是真的详细而且亲民。 链接:https://blog.lexfo.fr/cve-2017-11176-linux-kernel-exploitation-part3.html 链接:https://blog.youkuaiyun.com/vanbreaker/article/details/7664296 涉及到的一些宏 ...

weixin_42177005的博客 1万+

STM32CubeMX实战:FreeRTOS内存管理5种方案全解析(附heap_4避坑指南)

本文深入解析了STM32CubeMX环境下FreeRTOS的5种内存管理方案(heap_1到heap_5),重点介绍了heap_4的优化策略与避坑指南。通过对比分析各方案的特点、性能指标及适用场景,帮助开发者根据项目需求选择最优内存管理策略,提升嵌入式系统开发效率与稳定性。

aa123的博客 620

数学不好是原罪——高等数学笔记(汇总版)

这是本人之前考研的高数手写笔记,工科学硕数一考了146(满分150),笔记有一定参考价值,欢迎大家收藏借鉴。

xuuyann 5万+

list_for_each,list_for_each_entry和list_for_each_entry_safe

比较 共同点 1.list_for_each和list_for_each_entry都是遍历链表的两个宏,本质上都是for循环。 2.他们做的事情本质上都一样,A.获取链表头,B.判断链表项是不是链表头,C.指向链表的下一项。 3.他们的区别:list_for_each遍历的链表,其链表项不属于某个结构体。或者说不关心它是不是包含在某个结构体中。 区别 1.list_for_each_entry遍历的链表,其每一项都是某个结构体中的成员,单纯遍历链表还不行,还要找到包含这个链表项的结构体的地址,从而为下一

Wang20122013的博客 3806

交通仿真软件:SUMO_(1).SUMO基础知识

SUMO 中的交通网络由节点(junctions)和边(edges)组成。节点表示交叉口或路网的连接点,边表示连接节点之间的道路。节点:节点文件(.nod.xml)定义了网络中的所有节点。每个节点有一个唯一的 ID 和坐标。</边:边文件(.edg.xml)定义了连接节点的边。每个边有一个唯一的 ID、起点节点 ID 和终点节点 ID。</车辆文件(.vtype.xml)定义了不同类型的车辆。每个车辆类型可以有不同的参数,例如长度、最大速度、加速度等。</

kkchenjj的博客 1432

linux 内核机制--链表机制(三):list_for_each_entry_safe

list_for_each_entry_safe 是 Linux 内核中用于安全遍历链表的宏,特别适用于在遍历过程中可能需要删除当前节点的情况。它通过使用两个指针(pos 和 n)来确保即使删除当前节点,遍历过程也不会中断。宏的工作原理是预先保存下一个节点的位置,从而避免因链表结构变化导致的未定义行为或崩溃。示例代码展示了如何使用该宏遍历链表并删除特定值的节点。需要注意的是,虽然该宏提供了安全性,但也引入了额外的性能开销,因此在不需要删除节点的情况下,建议使用更高效的 list_for_each_entry

MHD0815的博客 740

【数字孪生与仿真技术】05:从原理到实战:MATLAB/Simulink在航空航天GNC系统开发中的深度解析(含全流程代码与认证指南)

摘要:本文系统阐述MATLAB/Simulink在航空航天制导、导航与控制(GNC)系统开发中的核心应用。通过解析GNC系统高保真动力学建模、多源导航传感器融合、鲁棒控制算法设计等关键技术原理,结合Virgin Orbit运载火箭、CubeSat等真实案例,展示从需求分析、模型搭建、仿真验证到代码生成与认证的完整开发流程。文中提供1200余行关键代码、8个可复用Simulink模型及详细执行结果展示,涵盖DO-178C认证支持、实时性能优化等工业级开发规范,为航空航天工程师、科研人员提供可落地的参考方案。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1656

基于Pycatia的智能孔特征识别技术:无参模型圆心自动化提取方案

基于Pycatia的智能孔特征识别技术:无参模型圆心自动化提取方案

KE17RS的博客 2877

关于container_of和list_for_each_entry 及其相关函数的分析

Linux代码看的比较多了,经常会遇到container_of和list_for_each_entry,特别是list_for_each_entry比较多,因为Linux经常用到链表,虽然知道这些函数的大概意思,但一旦出现一个类似的函数比如list_for_each_entry_safe就又会感到头大,所以下定决心分析总结一下这些函数的用法,以后再看到这些面孔的时候也会轻松很多,读Linux代码的

若海人生的专栏 1万+

nvidia系列教程-AGX-Orin usb3.0接口调试

NVIDIA Jetson AGX Orin 是一款高性能的嵌入式计算平台,适用于 AI 推理、机器人、自动驾驶等应用场景。本文将介绍如何对 AGX Orin 平台上的 USB 3.0 接口进行调试,包括硬件检查、软件配置以及常见问题的排查。本文主要介绍在AGX-Orin平台开启两个usb3.0口的方法。通过以上步骤,您可以有效地调试和优化 NVIDIA Jetson AGX Orin 上的 USB 3.0 接口。

flypig has a dream! 1502

list_for_each_entry详解

list_for_each_entry详解

Wanggj的博客 1万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

list_for_each_entry 详解

list_for_each_entry用法

alifrank的博客 1017

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

list_for_each_entry()函数分析

list_for_each原型: #define list_for_each(pos, head) \ for (pos = (head)->next, prefetch(pos->next); pos != (head); \ pos = pos->next, prefetch(pos->next))   它实际上...

weixin_30821731的博客 225

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Linux内核中list_head、list_for_each、list_entry、container_of之间的关系

原文:http://blog.youkuaiyun.com/hongchangfirst/article/details/7076225 作者:hongchangfirst Linux内核需要经常用到链表,所以为了避免重复的代码,就自己实现了一个循环双向链表。 首先我们先看一下list_head的定义,该结构体在linux/types.h中定义。 struct list_head

hongchangfirst 9800

linux内核学习笔记之——list_for_each_entry

在Linux内核源码中,经常要对链表进行操作,其中一个很重要的宏是list_for_each_entry: 意思大体如下: 假设只有两个结点,则第一个member代表head, list_for_each_entry的作用就是循环遍历每一个pos中的member子项。 图1: pos:                                                 

少想多做 871

list_for_each_entry和list_for_each_entry_safe

/**  * 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

xiaowen_10的专栏 6490

linux 的list_for_each_entry

比如list_for_each_entry,看名字只知道是遍历list,但一看里面的三个变量参数,有点懵逼。ptr是成员变量地址,type是结构体类型,member是成员变量在结构体声明里的名字称谓。pos = list_next_entry(pos, member)) //获取(pos)->member.next 所在结构体的地址。所以说 list_entry 是获取ptr所属的结构体地址。解释内容说是获取list的下一个成员指针,看代码是获取(pos)->member.next 所在结构体的地址。

baidu_16271159的博客 530
上一篇: Linux __setup宏解析
下一篇: C语言可变参数函数取参方法
LinuxWorking
博客等级 码龄10年 24粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值