Linux内核编程广泛使用的前向声明(Forward Declaration)
前向聲明
編程定律
先強(qiáng)調(diào)一點(diǎn):
在一切可能的場景,盡可能地使用前向聲明(Forward Declaration)。這符合信息隱蔽的原則。
一個(gè)例子
regmap
那么前向聲明究竟是個(gè)什么鬼?
在內(nèi)核寫代碼和看代碼的童鞋,經(jīng)常發(fā)現(xiàn)Linux內(nèi)核里面充斥著這樣的代碼,比如
include/vim linux/regulator/driver.h
文件中:
我們以regmap這個(gè)結(jié)構(gòu)體為例,這個(gè)地方就是一個(gè)前向聲明,告訴后面的代碼regmap是個(gè)結(jié)構(gòu)體,至于這個(gè)結(jié)構(gòu)體里面有什么鬼,不知道!
Linux可以說滿世界都在使用這個(gè)結(jié)構(gòu)體。滿世界都在使用聲明在include/linux/regmap.h中的regmap_write() regmap_read() 這樣的API,可以說無處不在,無處不用,比如drivers/rtc/rtc-at91sam9.c中的:
這樣的東西大家隨便一搜索,都可以搜索出來無數(shù)個(gè)。這樣看起來,regmap這個(gè)結(jié)構(gòu)體,應(yīng)該是一個(gè)跨模塊的API,它的整個(gè)結(jié)構(gòu)體長成怎么樣,應(yīng)該是出現(xiàn)在一個(gè)include/linux/級(jí)別的頂級(jí)跨模塊頭文件中了,這樣方便跨模塊引用這個(gè)結(jié)構(gòu)體。
但是,真實(shí)的情況卻讓你大跌眼鏡,regmap結(jié)構(gòu)體的具體成員長什么樣子,沒有出現(xiàn)在任何一個(gè)外部級(jí)別的頭文件里面,而是完全internal的(內(nèi)部的、內(nèi)部的、內(nèi)部的,各位童鞋!!!):
drivers/base/regmap/internal.h
既然它出現(xiàn)在drivers/base/regmap/internal.h,那么想必除了drivers/base/regmap/本身的內(nèi)部實(shí)現(xiàn)外,外部不可能引用drivers/base/regmap/internal.h這個(gè)頭文件。
所以,我們得出一個(gè)結(jié)論,盡管Linux滿世界都在使用struct regmap,但是除了drivers/base/regmap/內(nèi)部以外,其實(shí)外部沒有任何一個(gè)人知道regmap這個(gè)結(jié)構(gòu)體長成什么樣子!!
這是一種極其良好的「高內(nèi)聚、低耦合」設(shè)計(jì)。因?yàn)?#xff0c;drivers/base/regmap/外部所有的人,其實(shí)都只是在擁有regmap這個(gè)結(jié)構(gòu)體的指針,而并沒有訪問regmap結(jié)構(gòu)體其中的任何一個(gè)成員,其實(shí)也只有drivers/base/regmap/的內(nèi)部實(shí)現(xiàn)在訪問而已。
比如,regmap_write實(shí)現(xiàn)于:drivers/base/regmap/regmap.c文件,它的代碼如下:
這樣做帶來的一個(gè)極大好處是,drivers/base/regmap/外部的世界根本不需要知道regmap結(jié)構(gòu)體長成什么樣子,因?yàn)闆]人需要知道,它們都只是在訪問regmap的指針。
而drivers/base/regmap/內(nèi)部無論怎么修改regmap結(jié)構(gòu)體的實(shí)現(xiàn)和成員本身,對外部的世界根本不可見,修改regmap結(jié)構(gòu)體后,drivers/base/regmap/以外的模塊都不需要重新編譯。
相反,如果我們直接把regmap結(jié)構(gòu)體的內(nèi)部細(xì)節(jié)暴露在include/linux/regmap.h這個(gè)頭文件中,那么由于這個(gè)頭文件滿世界都被引用,你只要修改regmap結(jié)構(gòu)體本身,就會(huì)導(dǎo)致內(nèi)核無數(shù)模塊的增量編譯。
include/linux/regmap.h中暴露了regmap_config結(jié)構(gòu)體,這說明這個(gè)結(jié)構(gòu)體的內(nèi)容需要被regmap以外的模塊知道:
為什么,它涉及到具體的寄存器是如何讀寫的callback以及具體的寄存器pattern,這肯定是一個(gè)API基本的東西,本身就應(yīng)該是跨模塊的東西,所以它的長相出現(xiàn)在了include/linux/regmap.h這個(gè)頂級(jí)頭文件中。
對于一個(gè)外部模塊而言,它只需要能夠通過regmap.h公開暴露的小部分寄存器配置接口,來通過類似regmap_init_mmio()這個(gè)的API來填充regmap結(jié)構(gòu)體的內(nèi)部實(shí)現(xiàn)。比如drivers/rtc/rtc-at91sam9.c中的:
上述代碼中,rtc->gpbr是一個(gè)struct regmap指針,regmap_init_mmio()在內(nèi)部填充了regmap的本身實(shí)現(xiàn)。之后drivers/rtc/rtc-at91sam9.c再調(diào)用regmap_write()、regmap_read()的時(shí)候,這些API從regmap模塊內(nèi)部調(diào)用我們填充進(jìn)去的reg_bits、val_bits、reg_stride這些寄存器pattern,幫忙完成寄存器的最終讀寫。
畫一幅圖
理清關(guān)系
永遠(yuǎn)用高內(nèi)聚和低耦合的思想設(shè)計(jì)代碼。Linux內(nèi)核2000萬行的代碼,不這么設(shè)計(jì)肯定要崩盤。寫代碼不是得過且過。尤其做單片機(jī)寫裸奔程序的童鞋要特別注意,你們往往覺得玩Linux的童鞋代碼一層層套很傻逼,這是完全不正確的理解。
天天要帶娃,雞飛狗跳,沒時(shí)間寫,我隨便用碎片時(shí)間胡說八道的,不知道各位看官有什么感想?歡迎板磚,也歡迎打賞。
掃碼或長按關(guān)注
回復(fù)「?加群?」進(jìn)入技術(shù)群聊
總結(jié)
以上是生活随笔為你收集整理的Linux内核编程广泛使用的前向声明(Forward Declaration)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 源码阅读网站
- 下一篇: Linux源码安装包快速升级方法