C语言高级用法---container_of()

container of()函数简介       在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? 函数还可以这样定义??? 怎么还有0呢???  哎,算了,还是放弃吧。。。)。 这就是内核大佬们厉害的地方,随便两行代码就让我们怀疑人生,凡是都需要一个过程,慢慢来吧。        其实,原理很简单:  ... 阅读详情

在Linux内核源码中,实现和链表相关的接口list_entry()时,会调用container_of()宏定义,它的作用是:给定结构体中某个成员的地址、该结构体类型和该成员的名字获取这个成员所在的结构体变量的首地址。有点绕,没关系,接着往下看就能明白了。
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) );})

要看懂上述代码,需要知道三个关键点:

  1. typeof(),取变量或表达式类型,可参考之前typeof的文章
  2. typeof( ((type *)0)->member ),用typeof( ((struct apple *)0)->color ) 解释更易理解,它的作用是获取结构体apple中变量color的类型,可参考之前的文章
  3. offsetof(),获取结构体中某个成员相对于该结构体首元素地址的偏移量

好了,再开始解释container_of(),其三个入参含义:

  1. ptr:结构体变量中某个成员的地址
  2. type:结构体类型
  3. member:该结构体变量的具体名字

比如如下结构体struct ipstore,假设已经有一个变量struct ipstore *ist1;,并给ist1分配好了内存且进行了初始化,在已知结构体成员list的地址的情况下,获取list所在的结构体变量ist1的首地址。此时有人就会问了,这里ist1明明是已知的,这么做不是自己给自己找麻烦吗?这是个好问题,但是不要忘记,本文到目前为止只是讲解container_of()的含义,并没有说它适合用在什么样的场景下,因为有一种使用场景,当链表是通过list串起来的时候,此时并不知道ist1的首地址,反而是知道list的地址,这时container_of()就非常合适了,内核中的链表就是这么做的。

struct list_head {
    struct list_head *next;
    struct list_head  *prev;
};

struct ipstore{
    unsigned long time;
    __u32 addr[4];
    struct list_head list;
};

所以,调用container_of()时具体的传参如下所示,其返回的结果是ist1的地址。

container_of(ist1->list, struct ipstore, list)

如下测试代码,通过container_of()取得了ip1的地址。

void container_of_test()
{
    struct ipstore ip1;
    struct ipstore *p1;

    p1 = container_of(&ip1.list, struct ipstore, list);

    printf("ip1's addr:0x%0x\n", &ip1);
    printf("p1's  addr:0x%0x\n", p1);
}
[root@xxx c_base]# ./a.out
ip1's addr:0xa5fe1fe0
p1's  addr:0xa5fe1fe0
【C语言】花式操作之container_of()宏的用法   前段时间在做算法移植的时候遇到一个问题,源头直指一个名为container_of()的函数,该函数的花式写法也着实让人不禁多看几眼。该函数的定义如下: #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof 阅读详情

相关推荐

【C 高阶】详解 container_of 宏

1. 简介 container_of 宏在 Linux 内核中非常常见,只有涉及到链表结构的几乎都有它的身影,其主要功能是通过结构体变量的任一成员便可得到该结构体变量的首地址。所以知道为什么在链表中很常见吧?因为在链表中使用该宏可以快速地通任一成员定位到成员所属的节点首地址! 其源码为: #define container_of(ptr, type, member) ({ \ co...

Kong 869

container_of函数详解

可以说是内核中使用最为频繁的一个函数了,简单来说,它的主要作用就是根据我们结构体中的已知的成员变量的地址,来寻求该结构体的首地址,直接看图,更容易理解。了解完内部完整的实现手法之后,我们也可以手码一个。函数内部涉及的相关知识了然于胸,下面我们再来看。,该如何理解这个表达式呢?,下面我们一一拆解来看。函数中,主要用来断言判断。

u011029104的专栏 5501

【C语言】offsetof,typeof,container_of介绍及使用

offsetof,typeof,container_of介绍及使用场景举例

qq_37164857的博客 1145

container_of的用法

container_of的用法1. container_of的用途说明2. offsetof的定义3. container_of的定义4. 例子4.1 获取预编译文件test.i4.2 container_of宏定义中的“({})”解释 1. container_of的用途说明 container_of的主要作用是:通过已知的一个数据结构成员指针ptr,数据结构类型type,以及这个成员指针在这个数据结构中的成员名member,来获取指向这个数据结构的指针type *。 2. offsetof的定义 #

bruce.zc_wang 1万+

彻底吃透 C 语言 offsetof 和 container_of 宏(内核 / 嵌入式高频)

offsetof是 C 标准库<stddef.h>中提供的一个宏,作用:计算一个结构体的成员变量,相对于结构体首地址的字节偏移量。参数说明:type:结构体的类型名(比如member:该结构体中的成员变量名(比如中的age返回值:无符号整数(实际是size_t类型),表示该成员相对于结构体首地址的字节偏移量。是Linux 内核源码中定义的核心宏(没有纳入 C 标准库,但所有嵌入式 / C 开发都会用到),它是offsetof的逆运算,也是 C 语言的黑科技之一。✅核心作用(划重点,背下来)

2402_83157621的博客 1157

Ubuntu22.04 网络图标消失与连接故障排查指南(附实战修复流程)

本文详细介绍了Ubuntu22.04系统中网络图标消失与连接故障的排查与修复方法。通过ifconfig、dhclient等命令诊断问题,提供从紧急恢复网络连接到深度排查的完整解决方案,帮助用户快速恢复网络功能并预防类似问题再次发生。

weixin_28481133的博客 287

【C语言】container_of 宏定义

一. container_of(ptr, type, member) 宏二. container_of 宏的应用。

qq_34142812的博客 1282

别再只会用555了!手把手教你用运放和RC电路搭一个50Hz正弦波信号源(附Multisim仿真文件)

本文详细介绍了如何使用运放LM358和RC电路搭建一个精准的50Hz正弦波信号源,涵盖文氏电桥核心原理、单电源供电解决方案、Multisim仿真及实物调试技巧。通过实战指南和优化建议,帮助电子爱好者快速掌握低频信号生成技术,适用于各种测试和校准场景。

weixin_34116482的博客 364

C语言结构体中不得不知的技巧-offsetof()与 container_of()的用法

C语言结构体中不得不知的技巧-offsetof()与 container_of()的用法

物联网老王的博客,公众号同名 1854

用RFSoC ZU47DR搭建软件无线电原型:从零配置Vivado到生成第一个射频信号

本文详细介绍了如何使用Xilinx RFSoC ZU47DR开发板搭建软件无线电原型系统,从Vivado环境配置到生成首个射频信号的全流程。通过整合ARM处理器、FPGA逻辑和高速ADC/DAC,该平台为通信算法验证提供了高效解决方案,特别适合SDR开发者和通信工程师快速实现原型设计。

weixin_26763955的博客 591

第七天 Labview进阶(7.4 NI Vision简单使用)

NIVision机器视觉软件使用指南 摘要:NIVision是National Instruments推出的高效机器视觉软件,具有硬件无缝集成、图形化编程和工业级部署等优势。本文介绍了NIVision的安装步骤(需Vision Acquisition和Vision Development模块)及三个典型应用案例:1)实物检测通过IMAQCreate等模块实现物体识别与坐标定位;2)OCR检测利用IMAQOCR系列模块完成字符识别;3)几何模板匹配使用IMAQLearnGeometricPattern等模块实

weixin_38637405的博客 771

c语言container理解

这里面还出现了一个typeof关键字.那么,typeof(((type *)0)->member), (&((type *)0)->member) 到底是什么样的一种操作了?现在我们可以知道(&((type *)0)->member) 这种操作,就是返回member在type这种类型结构体中的相对地址偏移,注意是相对偏移而不是成员在内存中的地址。

xiebingsuccess的博客 1158

【推荐100个unity插件】unity易于使用模块化设计的天空、体积云和天气系统——Enviro 3

Enviro 3是一款功能强大的Unity天空与天气系统插件,提供动态天空、体积云、天气模拟等丰富功能。安装时需将预制体拖入场景并配置主相机,URP支持需激活深度纹理和添加渲染特性。模块化设计允许自由添加/移除时间、光照、雾效等模块,并通过API控制参数。推荐配合色调映射(如ACES模式)获得最佳视觉效果。插件支持季节、温湿度模拟及闪电风暴等特效,适用于需要逼真环境渲染的Unity项目。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2094

万字长文剖析C语言结构体的高级用法

关注、星标公众号,直达精彩内容ID:txp学Linux作者:txp 前言 ...

李肖遥的专栏 2433

[PCIe5.0] 2.2.7.1 TPH Rules

TPH 机制通过硬件提示优化数据流,适用于高性能计算和存储场景。

系统固件工程师 349

智元机器人开源具身仿真框架 Genie Sim 入门教程

GenieSim是AgiBot推出的具身智能仿真框架,提供完整闭环开发管道,包括轨迹生成、模型训练和基准测试。框架支持Docker容器化部署,要求Ubuntu 22.04和NVIDIA硬件环境。主要功能涵盖: 支持12种基准测试任务 提供ADER评估框架 集成UniVLA/RDT等基线模型 支持PICO/键盘遥操作 具备轨迹记录回放功能 提供完整API控制接口 开发者可通过Hugging Face获取场景资产,使用标准化ROS主题与仿真环境交互。框架特别优化了碰撞检测和抓取物理模拟,适用于从简单抓取到复杂操

2506_90492529的博客 2542

Linux 中C语言的一点高级用法

Linux 中C语言的一点高级用法

wubing_2010的专栏 1036

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Linux C: container_of()和offsetof()函数与结构体成员的偏移量计算

就内核的container_of()函数,发表一下个人见解。 在内核中,多处地方用到container_of()这个函数(如内核链表), 其定义在内核代码 include/linux/kernel.h中: /** * container_of - cast a member of a structure out to the containing structure * @ptr: ...

曾哥哥的博客 1184

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

container_of()宏

container_of前言表达式中的语句typeof()零指针取消引用offsetof(st, m)放在一起 前言 看内核源码时经常遇到这个宏,现在解释一下这个,记录备查。 第一张图说明了container_of(ptr, type, member)宏的原理 #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (

攻城狮 319

c语言中offset和container_of宏的讲解

1.offset宏的讲解 # define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 1)((type *) 0) =》0地址强制转化为type类型的指针; 2) ((type *)0)->MEMBER =》 访问type结构中的MEMBER数据成员 3) &(((type *)0)->MEMBER) =》去除type结构中数据成员member的地址 4) (size_t)(&(((type *

c243311364的博客 1032

container_of宏的一种高级用法

从数组的一个成员,反推出包含该数组的外围结构体 问题 驱动经常会注册各种回调,回调会对入参应用container_of宏,来得到外围对象的指针,从而访问外围对象的其他字段。 有的时候,回调函数的入参,并不是想要访问的结构体的儿子字段,而是孙子字段,甚至是重孙子字段,并且这种嵌套关系可能并不是简单的结构体嵌套,而是数组嵌套,例如这样的: struct board{ int slot; int ip; }; struct chassis{ int id; struct boar

六个九十度 472
上一篇: C语言高级用法---typeof( ((type *)0)->member )和offset_of()
下一篇: Linux内核中链表的实现
sweird
博客等级 码龄20年 336粉丝 103原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值