搞懂它,就可以把结构体玩活了~

正文
大家周末好,我是bug菌~
今天主要是跟大家详细聊聊container_of这个宏定义,非常经典的宏,只是一直没有抽时间细细品味,今天就跟大家一起来看看有何神奇之处:
1
offsetof
首先我们需要简单看看offsetof(TYPE, MEMBER) 这个宏定义,它是用于计算一个结构体中某个成员的偏移量。
其第一个参数 TYPE 是一个结构体类型,第二个参数 MEMBER 是 TYPE 中的一个成员变量名。
它将返回类型为 size_t 的整数,表示 MEMBER 相对于 TYPE 起始地址的偏移量。
基本原理是根据 C 语言的数据对齐机制,成员变量在类型定义中的相对位置决定了它的偏移量。
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 该宏定义使用了C语言中的指针运算和类型转换。具体实现步骤如下:
1、(TYPE *)0:将0强制类型转换为指向类型为TYPE的指针,得到了一个结构体TYPE的空指针。
2、&((TYPE *)0)->MEMBER:求出结构体类型TYPE中成员MEMBER的地址。其巧妙之处在于,由于空指针不指向任何对象,因此这个成员的地址就是相对于结构体首地址的偏移量。
3、(size_t):将偏移量转换为无符号整型数,以满足C语言标准库中对offsetof()返回值的类型要求。
该宏定义可以在编译时就直接计算出偏移量,避免了运行时的计算开销,因此比通过变量名访问成员的方式更为高效,通常用在需要直接访问结构体成员的底层代码中,例如在操作系统内核、嵌入式系统以及一些高性能计算应用中。
struct TestStruct { int value1; char value2; double value3;
}; size_t offset = offsetof(struct TestStruct, value2); 如上例,offset 变量将会存储 value2 相对于 TestStruct 起始地址的偏移量。在这种情况下,因为 TestStruct 中的 value1 通常占用了 4 个字节,value2 占用了 1 个字节,所以 value2 相对于结构体起始地址的偏移量应该是 4。
2
container_of
讲完offsetof,来到今天的主角container_of,container_of()是一个在linux内核中经常使用的宏,用于获取一个结构体成员指针所在它所属的结构体的指针,有点绕口,细细品味。
该宏包括也主要包括三个参数:
ptr:结构体中某个成员的指针;
type:结构体类型名称;
member:结构体中ptr指向的成员名称。
首先,宏container_of()确定了ptr指向的成员在结构体中的偏移(offset)。通过offsetof()宏就可以得到这个偏移,其参数为结构体类型和成员名称。得到偏移后,再通过减去偏移的方式得到指向整个结构体的指针,巧妙吧。
具体实现如下:
#define container_of(ptr, type, member) ({ \const typeof(((type *)0)->member) *__mptr = (ptr); \(type *)((char *)__mptr - offsetof(type, member)); }) 其中,typeof是GCC的一个扩展关键字,用于返回一个表达式的类型,可惜,大部分非GCC编译器不一定能支持。
假设ptr指向的成员变量的类型为T,__mptr就是一个指向T类型的指针。然后,调用offsetof()即可得到member在type类型中的偏移量,最后返回一个指向type类型的指针。
注意,尖括号不能省略,因为它表示类型转换。此外,container_of()宏使用了一个GCC的语言扩展"statement expression",即后面的{},可以在其中包含多条语句。
下面给出一个示例,用于说明container_of()的使用方法:
#include <stdio.h>
#include <stddef.h>#define container_of(ptr, type, member) ({ \const typeof(((type *)0)->member) *__mptr = (ptr); \(type *)((char *)__mptr - offsetof(type, member)); })struct student {int id;char name[20];
};int main() {struct student stu = {10001, "Zhang San"};char *pname = stu.name;struct student *pstu = container_of(pname, struct student, name);printf("ID: %d, Name: %s\n", pstu->id, pstu->name);return 0;
} 如上例,pname指向stu的name成员,通过container_of()宏获得了指向整个struct student结构体的指针pstu,然后就可以访问id和name成员了。
最后
好了,今天就跟大家分享这么多了,如果你觉得有所收获,一定记得点个赞+关注~
bug菌唯一、永久、免费分享嵌入式技术知识平台~

推荐专辑 点击蓝色字体即可跳转
☞ MCU进阶专辑 
☞ 嵌入式C语言进阶专辑 
☞ “bug说”专辑 
☞ 专辑|Linux应用程序编程大全
☞ 专辑|学点网络知识
☞ 专辑|手撕C语言
☞ 专辑|手撕C++语言
☞ 专辑|经验分享
☞ 专辑|电能控制技术
☞ 专辑 | 从单片机到Linux

相关文章:
搞懂它,就可以把结构体玩活了~
正文 大家周末好,我是bug菌~ 今天主要是跟大家详细聊聊container_of这个宏定义,非常经典的宏,只是一直没有抽时间细细品味,今天就跟大家一起来看看有何神奇之处: 1 offsetof 首先我们需要简单看看offsetof(TYPE, MEMBER) 这个宏定…...
基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖(四)
编辑员工和分类模块功能开发 1. 编辑员工1.1 需求分析与设计1.1.1 产品原型1.1.2 接口设计 1.2 代码开发1.2.1 回显员工信息功能1.2.2 修改员工信息功能 1.3 功能测试 2. 分类模块功能开发2.1 需求分析与设计2.1.1 产品原型2.1.2 接口设计2.1.3 表设计 2.2 代码实现2.2.1 Mappe…...
dcat admin 各种问题
样式问题 如何根据条件给表格数据栏添加背景色 use Illuminate\Support\Collection;protected function grid(){return Grid::make(new BookArticle(), function (Grid $grid) {... 其他代码// Collection的完整路径:Illuminate\Support\Collection;$grid->row…...
数据结构与算法(二)动态规划(Java)
目录 一、简介1.1 什么是动态规划?1.2 动态规划的两种形式1)自顶向下的备忘录法(记忆化搜索法)2)自底向上的动态规划3)两种方法对比 1.3 动态规划的 3 大步骤 二、小试牛刀:钢条切割2.1 题目描述…...
颜值实力“C位出道”:起亚EV6综合实力究竟怎么样?
作为起亚电动化转型的标杆之作,起亚EV6已在全球赢得广泛赞誉,连续斩获“2022欧洲年度汽车”及“2023北美年度汽车”等多项国际大奖,其GT版本更是荣获“2023年度世界性能车”,这些荣誉不仅标志着其设计和技术的国际认可,…...
继承和多态_Java零基础手把手保姆级教程(超详细)
文章目录 Java零基础手把手保姆级教程_继承和多态(超详细)1. 继承1.1 继承的实现(掌握)1.2 继承的好处和弊端(理解) 2. 继承中的成员访问特点2.1 继承中变量的访问特点(掌握)2.2 sup…...
AI:85-基于深度学习的自然场景生成与渲染
🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新中,…...
Windows电脑训练 RT-DETR 改进算法 (Ultralytics) 教程,改进RTDETR算法(包括使用训练、验证、推理教程)
手把手从零开始训练 RT-DETR 改进项目 (Ultralytics版本) 教程,改进RTDETR算法 本文以Windows服务器为例:从零开始使用Windows训练 RT-DETR 算法项目 《芒果剑指 RT-DETR 目标检测算法 改进》 适用于芒果专栏改进RT-DETR算法 文章目录 百度 RT-DETR 算法介绍改进网络代码汇…...
flask框架报错解决方法
1、报错 jinja2.exceptions.TemplateNotFound 解决方法:报错jinja2.exceptions.TemplateNotFound,template没找到,由于我之前直接将.html文件和.py文件直接放在同一目录下,经了解,需要新增一个 templates目录ÿ…...
Ubuntu18.04 安装docker教程
Ubuntu18.04 安装docker教程 1、前言 Docker Engine-Community 支持以下的 Ubuntu 版本: Xenial 16.04 (LTS)Bionic 18.04 (LTS)Cosmic 18.10Disco 19.04 Docker Engine-Community 支持以下CPU架构: x86_64(或 amd64)armhfarm…...
深入理解Git
目录 一、Git 的基本构造 1.1 关键对象类型 1.2 存储机制 二、Git 的内部工作 2.1 哈希和数据完整性 2.2 引用和可达性 2.3 分支和合并 2.4 垃圾回收 三、Git 高级特性 3.1 垃圾回收 3.2 钩子(Hooks) 3.3 子模块 四、常用命令 五、最佳实践…...
Leetcode_203.移除链表元素—C语言
目录 ❣️1.题目❣️ ❣️2.解答❣️ 💞方法一:暴力法 💞方法二: 尾插法 💞方法三:哨兵位法 ❣️1.题目❣️ 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.va…...
虹科方案 | 汽车电子电气架构设计仿真解决方案
来源:虹科汽车电子 虹科方案 | 汽车电子电气架构设计仿真解决方案 导读 本文将介绍面向服务(SOA)的汽车TSN网络架构,并探讨RTaW-Pegase仿真与设计软件在TSN网络设计中的应用。通过RTaW将设计问题分解,我们可以更好地理…...
Java6种单例模式写法
单例模式 某个类任何情况下只有一个实例,并提供一个全局访问点来获取该实例。Java6种单例模式:2种懒汉式,2种饿汉式 ,静态内部类 ,枚举类懒汉式 synchronized延迟加载 public class Singleton {private static Sing…...
Direct3D拾取
假设在屏幕上单击,击中的位置为点s(x,y)。由图可以看出,用户选中了茶壶。但是仅给出点s,应用程序还无法立即判断出茶壶是否被选中。所以针对这类问题,我们需要采用一项称为“拾 取(Picking)”的技术。 茶壶和屏幕点s之间的一种联…...
大洋钻探系列之二IODP 342航次是干什么的?(上)
本文简单介绍一下大洋钻探IODP 342航次,从中,我们一窥大洋钻探航次的风采。 IODP342的航次报告在网络上可以下载,英文名字叫《Integrated Ocean Drilling ProgramExpedition 342 Preliminary Report》,航次研究的主要内容是纽芬兰…...
离散时间系统模型
离散时间系统模型 离散时间系统模型是表示数字滤波器的方案。MATLAB 科学计算环境支持若干种离散时间系统模型,这些模型将在以下章节中介绍: 传递函数零极点增益状态空间部分分式展开式(残差形式)二阶节 (SOS)格型结构体卷积矩…...
Nginx学习(在 Docker 中使用 Nginx)
1. 安装Nginx 使用 docker pull nginx 下载最新的 Nginx Docker 镜像。 下载完毕后,使用 docker run -d -p 80:80 --name nginx nginx,即可启动 Nginx 容器。其中,-p 80:80 表示将容器的 80 端口映射到 主机的 80 端口;--name ng…...
【Java】集合(一)单列集合List
1.集合 可以动态保存任意多个对象,并提供了一系列的操作对象的方法:add、remove、set、get等。 2.集合框架体系 分为两大类: 单列集合和双列集合 3.List接口基本介绍 List接口是Collection接口的子接口 List集合类中元素有序࿰…...
实战 | 基于卷积神经网络的蘑菇识别微信小程序
一个不知名大学生,江湖人称菜狗 original author: Jacky Li Email : 3435673055qq.com Time of completion:2023.11.13 Last edited: 2023.11.13 导读:其实没啥难的,主要是随手搞了就发出来把,太久没有水过帖子了&…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...
GAN模式奔溃的探讨论文综述(一)
简介 简介:今天带来一篇关于GAN的,对于模式奔溃的一个探讨的一个问题,帮助大家更好的解决训练中遇到的一个难题。 论文题目:An in-depth review and analysis of mode collapse in GAN 期刊:Machine Learning 链接:...
SQL注入篇-sqlmap的配置和使用
在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap,但是由于很多朋友看不了解命令行格式,所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习,链接:https://wwhc.lanzoue.com/ifJY32ybh6vc…...
LTR-381RGB-01RGB+环境光检测应用场景及客户类型主要有哪些?
RGB环境光检测 功能,在应用场景及客户类型: 1. 可应用的儿童玩具类型 (1) 智能互动玩具 功能:通过检测环境光或物体颜色触发互动(如颜色识别积木、光感音乐盒)。 客户参考: LEGO(乐高&#x…...
