宋宝华: Linux内核编程广泛使用的前向声明(Forward Declaration)
本文系转载,著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:宋宝华
来源: 微信公众号linux阅码场(id: linuxdev)

前向声明
编程定律
先强调一点:在一切可能的场景,尽可能地使用前向声明(Forward Declaration)。这符合信息隐蔽的原则。
一个例子
regmap
那么前向声明究竟是个什么鬼?在内核写代码和看代码的童鞋,经常发现Linux内核里面充斥着这样的代码,比如
include/vim linux/regulator/driver.h
文件中:

我们以regmap这个结构体为例,这个地方就是一个前向声明,告诉后面的代码regmap是个结构体,至于这个结构体里面有什么鬼,不知道!
Linux可以说满世界都在使用这个结构体。满世界都在使用声明在include/linux/regmap.h中的regmap_write()、regmap_read()这样的API,可以说无处不在,无处不用,比如drivers/rtc/rtc-at91sam9.c中的:

这样的东西大家随便一搜索,都可以搜索出来无数个。这样看起来,regmap这个结构体,应该是一个跨模块的API,它的整个结构体长成怎么样,应该是出现在一个include/linux/级别的顶级跨模块头文件中了,这样方便跨模块引用这个结构体。
但是,真实的情况却让你大跌眼镜,regmap结构体的具体成员长什么样子,没有出现在任何一个外部级别的头文件里面,而是完全internal的(内部的、内部的、内部的,各位童鞋!!!):
drivers/base/regmap/internal.h

既然它出现在drivers/base/regmap/internal.h,那么想必除了drivers/base/regmap/本身的内部实现外,外部不可能引用drivers/base/regmap/internal.h这个头文件。
所以,我们得出一个结论,尽管Linux满世界都在使用struct regmap,但是除了drivers/base/regmap/内部以外,其实外部没有任何一个人知道regmap这个结构体长成什么样子!!
这是一种极其良好的“高内聚、低耦合”设计。因为,drivers/base/regmap/外部所有的人,其实都只是在拥有regmap这个结构体的指针,而并没有访问regmap结构体其中的任何一个成员,其实也只有drivers/base/regmap/的内部实现在访问而已。
比如,regmap_write实现于:drivers/base/regmap/regmap.c文件,它的代码如下:

这样做带来的一个极大好处是,drivers/base/regmap/外部的世界根本不需要知道regmap结构体长成什么样子,因为没人需要知道,它们都只是在访问regmap的指针!
而drivers/base/regmap/内部无论怎么修改regmap结构体的实现和成员本身,对外部的世界根本不可见,修改regmap结构体后,drivers/base/regmap/以外的模块都不需要重新编译!
相反,如果我们直接把regmap结构体的内部细节暴露在include/linux/regmap.h这个头文件中,那么由于这个头文件满世界都被引用,你只要修改regmap结构体本身,就会导致内核无数模块的增量编译!
include/linux/regmap.h中暴露了regmap_config结构体,这说明这个结构体的内容需要被regmap以外的模块知道:

...
为什么,它涉及到具体的寄存器是如何读写的callback以及具体的寄存器pattern,这肯定是一个API基本的东西,本身就应该是跨模块的东西,所以它的长相出现在了include/linux/regmap.h这个顶级头文件中。
对于一个外部模块而言,它只需要能够通过regmap.h公开暴露的小部分寄存器配置接口,来通过类似regmap_init_mmio()这个的API来填充regmap结构体的内部实现。比如drivers/rtc/rtc-at91sam9.c中的:

上述代码中,rtc->gpbr是一个struct regmap指针,regmap_init_mmio()在内部填充了regmap的本身实现。之后drivers/rtc/rtc-at91sam9.c再调用regmap_write()、regmap_read()的时候,这些API从regmap模块内部调用我们填充进去的reg_bits、val_bits、reg_stride这些寄存器pattern,帮忙完成寄存器的最终读写。
画一幅图
理清关系

永远用高内聚和低耦合的思想设计代码。Linux内核2000万行的代码,不这么设计肯定要崩盘。写代码不是得过且过。尤其做单片机写裸奔程序的童鞋要特别注意,你们往往觉得玩Linux的童鞋代码一层层套很傻逼,这是完全不正确的理解。
天天要带娃,鸡飞狗跳,没时间写,我随便用碎片时间胡说八道的,不知道各位看官有什么感想?欢迎板砖,也欢迎打赏。
更多精彩更新中……欢迎关注微信公众号:linux阅码场(id: linuxdev)
宋宝华: Linux内核编程广泛使用的前向声明(Forward Declaration)的更多相关文章
- 宋宝华: 关于Linux进程优先级数字混乱的彻底澄清
宋宝华: 关于Linux进程优先级数字混乱的彻底澄清 原创: 宋宝华 Linux阅码场 9月20日 https://mp.weixin.qq.com/s/44Gamu17Vkl77OGV2KkRmQ ...
- 宋宝华:Linux设备驱动框架里的设计模式之——模板方法(Template Method)
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前言 <设计模式>这本经典 ...
- 宋宝华:关于ARM Linux原子操作的实现
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 竞态无所不在 首先我们要理解竞态(ra ...
- 宋宝华:Docker 最初的2小时(Docker从入门到入门)
本文系转载,著作权归作者所有. 商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 最初的2小时,你会爱上Docker, ...
- 宋宝华:关于Ftrace的一个完整案例
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) Ftrace简介 Ftrace是Lin ...
- 初探linux内核编程,参数传递以及模块间函数调用
一.前言 我们一起从3个小例子来体验一下linux内核编程.如下: 1.内核编程之hello world 2.模块参数传递 3.模块间 ...
- Linux内核编程规范与代码风格
source: https://www.kernel.org/doc/html/latest/process/coding-style.html translated by trav, travmym ...
- Linux内核编程-0:来自内核的 HelloWorld
Linux内核编程一直是我很想掌握的一个技能.如果问我为什么,我也说不上来. 也许是希望有一天自己的ID也出现在内核开发组的邮件列表里?或是内核发行文件的CREDITS文件上? 也许是吧.其实更多的, ...
- linux内核编程入门 hello world
注意: Makefile 文件的命名注意M需要大写,否则会报错. 在Makefile文件中make命令前应为tab制表符. 下文转载至:https://blog.csdn.net/bingqing07 ...
随机推荐
- C# 8 - using声明 和 异步流
这两个主题没什么关系,但是怕文章太短被移除主页. using声明 using语句块 尽管.NET Core运行时有垃圾收集器(GC)来负责内存清理工作,但是我们还是要自己确保当非托管资源不再使用的时候 ...
- 设计模式(四)Factory Method模式
简单来说,用Template Method模式来构建生成实例的工厂,就是Factory Method模式.在这个模式中,父类决定实例的生成方式,但不决定所要生成的具体的类,具体的处理全部交给子类负责. ...
- Andriod Studio设置类默认签名模板
- Texture to texture2D以及texture2D像素反转
private void SaveRenderTextureToPNG(Texture inputTex, string file) { RenderTexture temp = RenderText ...
- C#控件的简单应用
listview 创建columns: ImageList imgList = new ImageList(); imgList.ImageSize = , ); FaceListview.Small ...
- MongoDB一次节点宕机引发的思考(源码剖析)
目录 简介 日志分析 副本集 如何实现 Failover 心跳的实现 electionTimeout 定时器 业务影响评估 参考链接 声明:本文同步发表于 MongoDB 中文社区,传送门: http ...
- Mycat分布式数据库架构解决方案--配置defaultAccount属性报错解决方案
echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 该文章 ...
- 热门开源网关的性能对比:Goku > Kong > Tyk
不多说,先展示最后的性能测试结果 我们将Goku与市场上的其他同类热门产品进行比较,使用相同的环境和条件,测试以下产品:Goku.Kong.Tyk.简单介绍下, Goku API Gateway (中 ...
- docker 和 FastDFS上传和下载文件
1,从仓库拉取镜像 sudo docker image pull delron/fastdfs 也可以解压已经打包好的镜像文件 $ sudo docker load -i 文件路径/fastdfs_d ...
- 谁说搞Java的不能玩机器学习?
简介 机器学习在全球范围内越来越受欢迎和使用. 它已经彻底改变了某些应用程序的构建方式,并且可能会继续成为我们日常生活中一个巨大的(并且正在增加的)部分. 没有什么包装且机器学习并不简单. 它对许多人 ...