網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
C語(yǔ)言中的__attribute__((weak)) 與?attribute?((weakref())
引言:最近在看 linux 中一些驅(qū)動(dòng)代碼。驅(qū)動(dòng)代碼中為了實(shí)現(xiàn)程序的擴(kuò)展性和兼容性用了很多 C 語(yǔ)言中的高級(jí)特性。本節(jié)就來(lái)談一談 C 語(yǔ)言中的弱符號(hào)和弱引用的用法。
弱符號(hào)
弱符號(hào)是指在定義或者聲明一個(gè)對(duì)象(變量、結(jié)構(gòu)體成員、函數(shù))時(shí),在對(duì)象的前面添加?__attribute__((weak))
?標(biāo)志所得到的對(duì)象符號(hào)。如下所示函數(shù)即為一個(gè)弱對(duì)象符號(hào)?void test_weak_attr(void)
,或者稱(chēng)該函數(shù)是弱函數(shù)屬性的、虛函數(shù)。
__attribute__((weak)) void test_weak_attr(void) // 或者使用如下樣式的定義,兩者等效 void __attribute__((weak)) test_weak_attr(void) { printf("Weak Func!\r\n"); }
弱符號(hào)的作用與示例
弱符號(hào)是相對(duì)于強(qiáng)符號(hào)而言的,在定義或者聲明變量、函數(shù)時(shí),未添加?__attribute__((weak))
?標(biāo)識(shí)的就默認(rèn)為強(qiáng)符號(hào)。如下,最普通的函數(shù)定義,就是定義了一個(gè)強(qiáng)符號(hào) void test_strong_ref(void):
void test_weak_attr(void) { printf("this is a strong func\r\n"); }
驅(qū)動(dòng)程序往往需要考慮兼容性,因?yàn)橐嫒魏芏鄰S商的不同型號(hào)的設(shè)備。若驅(qū)動(dòng)程序中使用強(qiáng)符號(hào)定義一些與適配的設(shè)備的特性相關(guān)的功能,則下次適配其他設(shè)備時(shí),該強(qiáng)符號(hào)函數(shù)可能需要被修改,以兼容新的設(shè)備。當(dāng)適配的設(shè)備很多時(shí),頻繁地更改驅(qū)動(dòng)代碼將破壞驅(qū)動(dòng)的可維護(hù)性。
弱符號(hào)的出現(xiàn)可以很好地解決該問(wèn)題。弱符號(hào)的對(duì)象具有可以被重定義的功能(即可以被重載)。下面通過(guò)測(cè)試說(shuō)明弱符號(hào)這種可被重載的特性。
在 test_weak_attr.c 程序中定義如下弱函數(shù):
// test_weak_attr.c #include <stdio.h> __attribute__((weak)) void test_weak_attr(void) { printf("this is a weak func\r\n"); }
在 main.c 中定義如下程序:
// main.c void test_weak_attr(void) { printf("this is a strong func\r\n"); } void app_main(void) { printf("init done\r\n"); test_weak_attr(); }
編譯運(yùn)行該 main.c 程序,得到的結(jié)果是什么樣子的呢?
this is a strong func
將 main.c 中的 void test_weak_attr(void) 函數(shù)注釋掉,再重新編譯運(yùn)行程序得到的結(jié)果是:
this is a weak func
小結(jié):在使用弱符號(hào)函數(shù)時(shí),我們可以重新定義一個(gè)同名的強(qiáng)符號(hào)函數(shù)來(lái)替代它;若沒(méi)有重新定義一個(gè)強(qiáng)函數(shù)來(lái)替換它,就使用弱函數(shù)的實(shí)現(xiàn)。弱函數(shù)就好像是一個(gè)可以被替換的“默認(rèn)函數(shù)”。
值得一提的是,舊版本的編譯器還可以使用如下方式的定義(僅聲明無(wú)效)將一個(gè)對(duì)象定義為一個(gè)弱對(duì)象:
__weak void f(void) { //code }
在 linux 的一些代碼中,__weak
?其實(shí)就是通過(guò)?__attribute__((weak))
的重命名,兩者等效。
弱引用
弱引用是在聲明一個(gè)對(duì)象時(shí),通過(guò)__attribute__ ((weakref())
?定義一個(gè)符號(hào)的引用關(guān)系。如下所示即定義 test_weakref() 函數(shù)弱引用 test_weak_ref() 函數(shù)。
static void test_weakref(void) __attribute__ ((weakref("test_weak_ref")));
弱引用是相對(duì)于強(qiáng)引用而言的。未通過(guò)?__attribute__ ((weakref())
?的符號(hào)和實(shí)現(xiàn)代碼之間的關(guān)系是強(qiáng)引用。如下即為一個(gè)強(qiáng)引用函數(shù)。它直接給出了 函數(shù) test_strong_ref(void)
的實(shí)現(xiàn)。
static void test_strong_ref(void) { printf("this is a strong ref\r\n"); }
在編譯程序的時(shí)候,我們可以直接使用 test_strong_ref(void)
而不必?fù)?dān)心編譯不通過(guò)。如果,我沒(méi)有時(shí)間去實(shí)現(xiàn) test_strong_ref(void) ,還想在程序里先使用該函數(shù)那該如何呢?(是的,就是想白嫖,不想實(shí)現(xiàn),還想先在程序里使用這個(gè)函數(shù))。
這個(gè)時(shí)候弱引用就派上用場(chǎng)了。可以先將該函數(shù)定義為弱引用插入到代碼中,待后期有時(shí)間再慢慢優(yōu)化代碼實(shí)現(xiàn)這個(gè)函數(shù)完整的功能。下面結(jié)合測(cè)試進(jìn)行說(shuō)明。
測(cè)試代碼1:
static void test_weakref(void) __attribute__ ((weakref("test_weak_ref"))); void app_main(void) { printf("init done\r\n"); if (test_weakref) { test_weakref(); } else { printf("There is no weakref\r\n"); } }
測(cè)試結(jié)果:
There is no weakref
測(cè)試代碼2:
void test_weak_ref(void) { printf("this is a weak ref\n"); } static void test_weakref(void) __attribute__ ((weakref("test_weak_ref"))); void app_main(void) { printf("init done\r\n"); if (test_weakref) { test_weakref(); } else { printf("There is no weakref\r\n"); } }
測(cè)試結(jié)果:
this is a weak ref
小結(jié): 強(qiáng)引用,在未定義該強(qiáng)引用的實(shí)現(xiàn)時(shí),編譯會(huì)報(bào)錯(cuò)誤:未定義的引用。弱引用允許定義一個(gè)未實(shí)現(xiàn)(未實(shí)例化)的對(duì)象,這在編譯的時(shí)候會(huì)將該對(duì)象處理成?NULL
,編譯器并不會(huì)報(bào)錯(cuò)。通過(guò)使用弱引用可以實(shí)現(xiàn)后期優(yōu)化代碼的功能。而避免改動(dòng)使用該函數(shù)的地方。使用弱函數(shù)可以實(shí)現(xiàn)類(lèi)似“鉤子(hook)"函數(shù)的功能。
實(shí)際上,包括C、python、go 編程語(yǔ)言在內(nèi)的很多語(yǔ)言 都有類(lèi)似用法,本篇文章敘述的方法同樣適用于這些語(yǔ)言的相關(guān)開(kāi)發(fā)。
注意:弱引用僅在靜態(tài)編譯中有效,動(dòng)態(tài)鏈接中可能無(wú)效。
總結(jié)
弱符號(hào)、弱引用都是增強(qiáng)程序的可維護(hù)性的方法。弱符號(hào)通過(guò)可以被重定義的特性,實(shí)現(xiàn)可以被替換實(shí)現(xiàn)。弱引用通過(guò)可以暫時(shí)使用一個(gè)未定義的函數(shù)的功能,實(shí)現(xiàn)允許后期再實(shí)現(xiàn)該函數(shù)具體功能,而不必?fù)?dān)心編譯不通過(guò)。
原文鏈接:https://blog.csdn.net/wangyx1234/article/details/123754438
相關(guān)推薦
- 2022-06-21 c語(yǔ)言詳解動(dòng)態(tài)內(nèi)存分配及常見(jiàn)錯(cuò)誤的解決_C 語(yǔ)言
- 2022-04-07 你知道怎么基于?React?封裝一個(gè)組件嗎_React
- 2022-05-13 Linux操作系統(tǒng)筆記——GCC編譯器
- 2023-02-14 使用PowerShell獲取Trustedinstaller權(quán)限的問(wèn)題_PowerShell
- 2022-09-24 C++實(shí)現(xiàn)并優(yōu)化異常系統(tǒng)_C 語(yǔ)言
- 2021-11-27 Linux開(kāi)機(jī)自啟動(dòng)服務(wù)兩種方式介紹_Linux
- 2022-09-16 Python中的socket網(wǎng)絡(luò)模塊介紹_python
- 2022-09-17 Python?自動(dòng)控制原理?control的詳細(xì)解說(shuō)_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支