宋寶華: Linux內核編程普遍使用的前向聲明(Forward Declaration)

本文系轉載,著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。linux

做者:宋寶華編程

來源: 微信公衆號linux閱碼場(id: linuxdev)vim

file


前向聲明

編程定律

先強調一點:在一切可能的場景,儘量地使用前向聲明(Forward Declaration)。這符合信息隱蔽的原則。微信

一個例子

regmap

那麼前向聲明到底是個什麼鬼?在內核寫代碼和看代碼的童鞋,常常發現Linux內核裏面充斥着這樣的代碼,好比ide

include/vim linux/regulator/driver.h設計

文件中:3d

file

咱們以regmap這個結構體爲例,這個地方就是一個前向聲明,告訴後面的代碼regmap是個結構體,至於這個結構體裏面有什麼鬼,不知道!指針

Linux能夠說滿世界都在使用這個結構體。滿世界都在使用聲明在include/linux/regmap.h中的regmap_write()、regmap_read()這樣的API,能夠說無處不在,無處不用,好比drivers/rtc/rtc-at91sam9.c中的:blog

file

這樣的東西你們隨便一搜索,均可以搜索出來無數個。這樣看起來,regmap這個結構體,應該是一個跨模塊的API,它的整個結構體長成怎麼樣,應該是出如今一個include/linux/級別的頂級跨模塊頭文件中了,這樣方便跨模塊引用這個結構體。接口

可是,真實的狀況卻讓你大跌眼鏡,regmap結構體的具體成員長什麼樣子,沒有出如今任何一個外部級別的頭文件裏面,而是徹底internal的(內部的、內部的、內部的,各位童鞋!!!):

drivers/base/regmap/internal.h

file

既然它出如今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文件,它的代碼以下:

file

這樣作帶來的一個極大好處是,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之外的模塊知道:

file

...

爲何,它涉及到具體的寄存器是如何讀寫的callback以及具體的寄存器pattern,這確定是一個API基本的東西,自己就應該是跨模塊的東西,因此它的長相出如今了include/linux/regmap.h這個頂級頭文件中。

對於一個外部模塊而言,它只須要可以經過regmap.h公開暴露的小部分寄存器配置接口,來經過相似regmap_init_mmio()這個的API來填充regmap結構體的內部實現。好比drivers/rtc/rtc-at91sam9.c中的:

file

上述代碼中,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,幫忙完成寄存器的最終讀寫。

畫一幅圖

理清關係

file

永遠用高內聚和低耦合的思想設計代碼。Linux內核2000萬行的代碼,不這麼設計確定要崩盤。寫代碼不是得過且過。尤爲作單片機寫裸奔程序的童鞋要特別注意,大家每每以爲玩Linux的童鞋代碼一層層套很傻逼,這是徹底不正確的理解。

每天要帶娃,雞飛狗跳,沒時間寫,我隨便用碎片時間胡說八道的,不知道各位看官有什麼感想?歡迎板磚,也歡迎打賞。

更多精彩更新中……歡迎關注微信公衆號:linux閱碼場(id: linuxdev)

相關文章
相關標籤/搜索