網站首頁 編程語言 正文
C語言中的__attribute__((weak)) 與?attribute?((weakref())
引言:最近在看 linux 中一些驅動代碼。驅動代碼中為了實現程序的擴展性和兼容性用了很多 C 語言中的高級特性。本節就來談一談 C 語言中的弱符號和弱引用的用法。
弱符號
弱符號是指在定義或者聲明一個對象(變量、結構體成員、函數)時,在對象的前面添加?__attribute__((weak))
?標志所得到的對象符號。如下所示函數即為一個弱對象符號?void test_weak_attr(void)
,或者稱該函數是弱函數屬性的、虛函數。
__attribute__((weak)) void test_weak_attr(void) // 或者使用如下樣式的定義,兩者等效 void __attribute__((weak)) test_weak_attr(void) { printf("Weak Func!\r\n"); }
弱符號的作用與示例
弱符號是相對于強符號而言的,在定義或者聲明變量、函數時,未添加?__attribute__((weak))
?標識的就默認為強符號。如下,最普通的函數定義,就是定義了一個強符號 void test_strong_ref(void):
void test_weak_attr(void) { printf("this is a strong func\r\n"); }
驅動程序往往需要考慮兼容性,因為要兼任很多廠商的不同型號的設備。若驅動程序中使用強符號定義一些與適配的設備的特性相關的功能,則下次適配其他設備時,該強符號函數可能需要被修改,以兼容新的設備。當適配的設備很多時,頻繁地更改驅動代碼將破壞驅動的可維護性。
弱符號的出現可以很好地解決該問題。弱符號的對象具有可以被重定義的功能(即可以被重載)。下面通過測試說明弱符號這種可被重載的特性。
在 test_weak_attr.c 程序中定義如下弱函數:
// 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(); }
編譯運行該 main.c 程序,得到的結果是什么樣子的呢?
this is a strong func
將 main.c 中的 void test_weak_attr(void) 函數注釋掉,再重新編譯運行程序得到的結果是:
this is a weak func
小結:在使用弱符號函數時,我們可以重新定義一個同名的強符號函數來替代它;若沒有重新定義一個強函數來替換它,就使用弱函數的實現。弱函數就好像是一個可以被替換的“默認函數”。
值得一提的是,舊版本的編譯器還可以使用如下方式的定義(僅聲明無效)將一個對象定義為一個弱對象:
__weak void f(void) { //code }
在 linux 的一些代碼中,__weak
?其實就是通過?__attribute__((weak))
的重命名,兩者等效。
弱引用
弱引用是在聲明一個對象時,通過__attribute__ ((weakref())
?定義一個符號的引用關系。如下所示即定義 test_weakref() 函數弱引用 test_weak_ref() 函數。
static void test_weakref(void) __attribute__ ((weakref("test_weak_ref")));
弱引用是相對于強引用而言的。未通過?__attribute__ ((weakref())
?的符號和實現代碼之間的關系是強引用。如下即為一個強引用函數。它直接給出了 函數 test_strong_ref(void)
的實現。
static void test_strong_ref(void) { printf("this is a strong ref\r\n"); }
在編譯程序的時候,我們可以直接使用 test_strong_ref(void)
而不必擔心編譯不通過。如果,我沒有時間去實現 test_strong_ref(void) ,還想在程序里先使用該函數那該如何呢?(是的,就是想白嫖,不想實現,還想先在程序里使用這個函數)。
這個時候弱引用就派上用場了。可以先將該函數定義為弱引用插入到代碼中,待后期有時間再慢慢優化代碼實現這個函數完整的功能。下面結合測試進行說明。
測試代碼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"); } }
測試結果:
There is no weakref
測試代碼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"); } }
測試結果:
this is a weak ref
小結: 強引用,在未定義該強引用的實現時,編譯會報錯誤:未定義的引用。弱引用允許定義一個未實現(未實例化)的對象,這在編譯的時候會將該對象處理成?NULL
,編譯器并不會報錯。通過使用弱引用可以實現后期優化代碼的功能。而避免改動使用該函數的地方。使用弱函數可以實現類似“鉤子(hook)"函數的功能。
實際上,包括C、python、go 編程語言在內的很多語言 都有類似用法,本篇文章敘述的方法同樣適用于這些語言的相關開發。
注意:弱引用僅在靜態編譯中有效,動態鏈接中可能無效。
總結
弱符號、弱引用都是增強程序的可維護性的方法。弱符號通過可以被重定義的特性,實現可以被替換實現。弱引用通過可以暫時使用一個未定義的函數的功能,實現允許后期再實現該函數具體功能,而不必擔心編譯不通過。
原文鏈接:https://blog.csdn.net/wangyx1234/article/details/123754438
相關推薦
- 2022-11-01 golang連接MongoDB數據庫及數據庫操作指南_Golang
- 2022-08-22 Python利用watchdog模塊監控文件變化_python
- 2022-08-10 對WPF中的TreeView實現右鍵選定_C#教程
- 2023-06-05 C++頭文件和cpp文件的原理分析_C 語言
- 2021-12-05 密碼學之apache部署https介紹_Linux
- 2022-03-16 Quartz.Net使用方法詳解_C#教程
- 2022-02-28 獲取元素的寬度,高度
- 2022-04-15 C語言?使用qsort函數來進行快速排序_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支