0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

ARM中關(guān)鍵字的具體使用

技術(shù)讓夢(mèng)想更偉大 ? 來(lái)源:CSDN-ZC·Shou ? 2023-02-10 15:06 ? 次閱讀

今天在使用 Keil (主要是 armcc 編譯器)編譯代碼(華大的 MCU 驅(qū)動(dòng)庫(kù)hc32f46x_interrupts.h / c)的時(shí)候遇到了有 __weak 關(guān)鍵字的函數(shù)不起作用的問題,甚是奇怪。之前對(duì)于 __weak 關(guān)鍵字一直是一個(gè)簡(jiǎn)單的認(rèn)知:「編譯器自動(dòng)使用沒有 __weak 的同名函數(shù)(如果有的話)替換有 __weak 關(guān)鍵字的同名函數(shù),__weak 函數(shù)可以沒有定義,且編譯器不會(huì)報(bào)錯(cuò)!」 至于這個(gè)參數(shù)詳細(xì)的使用細(xì)節(jié)一直是一知半解,今天借此機(jī)會(huì),以 GCC 作為對(duì)比,來(lái)學(xué)習(xí)一下 ARM 中的 __weak 關(guān)鍵字的具體使用!

來(lái)源

使用過 GCC 以及有 linux 編程經(jīng)驗(yàn)的人,對(duì)于這個(gè)關(guān)鍵字應(yīng)該不陌生。GNU 的編譯器(gcc)擴(kuò)展了一個(gè)關(guān)鍵字 __attribute__,通過該關(guān)鍵字,用戶可以在聲明時(shí)指定特殊的屬性,使用時(shí)該關(guān)鍵字后跟雙括號(hào)內(nèi)的屬性,例如:__attribute__((屬性名字))。屬性名字都是定義好的,Weak 屬性就是其中之一:__attribute__((weak))。在 linux 源碼中,該關(guān)鍵字非常常見:

bb8d281c-a862-11ed-bfe3-dac502259ad0.png

GCC 不多介紹,重點(diǎn)關(guān)注 ARM。在 ARM 編譯器(armcc)中,支持和 GCC 相同的關(guān)鍵字 __attribute__,使用方式也基本相同,如下:

__attribute__((attribute1,attribute2,...))//例如:void*Function_Attributes_malloc_0(intb)__attribute__((malloc));
__attribute__((__attribute1__,__attribute2__,...))//例如:staticintb__attribute__((__unused__));
12

當(dāng)函數(shù)屬性發(fā)生沖突時(shí),編譯器將使用更安全或更強(qiáng)的一個(gè)

除此之外,ARM 編譯器(armcc)還擴(kuò)展了一個(gè)關(guān)鍵字 __weak,例如:__weak void f(void); 或者 __weak int i;。ARM 的匯編器(armasm)以另一種方式 [WEAK] 支持該特性。

「注意:」在許多源碼中,經(jīng)常通過宏定義的形式來(lái)定義關(guān)鍵字,例如 上面linux 中的 __weak 就是 宏定義的 __attribute__((weak))

強(qiáng)/弱符號(hào)

在 GCC 中,被 __attribute__((weak)) 修飾的符號(hào),我們稱之為 「弱符號(hào)(Weak Symbol)」。例如:弱函數(shù)、弱變量;沒有 __attribute__((weak)) 修飾的符號(hào)被稱為「強(qiáng)符號(hào)」。在 ARM 中,沒有弱符號(hào)和強(qiáng)符號(hào)這種叫法,只有個(gè)「弱引用(Weak References)」 和 「非弱引用(non-weak reference )」 、 「弱定義(Weak definitions)」 和 「非弱定義(non-weak definition)」 的介紹章節(jié)。

編譯器和匯編器都可以輸出弱符號(hào)。

非弱引用

非弱引用就是我們平常使用的對(duì)于非弱函數(shù)或者弱變量的引用。如果鏈接器無(wú)法在到目前為止已加載內(nèi)容中解析對(duì)正常非弱符號(hào)的引用問題,則 「它會(huì)嘗試通過在庫(kù)中找到符號(hào)」 來(lái)解決此問題:

如果找不到此類引用,則鏈接器將報(bào)告錯(cuò)誤。

如果解析了這樣的引用,則從入口點(diǎn)可以通過至少一個(gè)非弱引用來(lái)訪問的節(jié)區(qū)被標(biāo)記為已使用。這樣可以確保鏈接器不會(huì)將該節(jié)作為未使用的節(jié)刪除。 每個(gè)非弱引用都必須通過一個(gè)定義來(lái)解決。 如果有多個(gè)定義,則鏈接器將報(bào)告錯(cuò)誤。

弱引用

「引用弱聲明的函數(shù)或者變量的引用即為弱引用。」 鏈接器不會(huì)從庫(kù)中加載對(duì)象來(lái)解析弱引用。僅當(dāng)由于其他原因在鏡像中包含了定義時(shí),它才能解析弱引用。「弱引用不會(huì)導(dǎo)致鏈接器將包含定義的節(jié)區(qū)標(biāo)記為已使用,因此鏈接器可能會(huì)將其標(biāo)記為未使用而刪除。」

__weak

__weak 關(guān)鍵字可以應(yīng)用于函數(shù)和變量的聲明以及函數(shù)定義。

聲明

__weak 可以用于函數(shù)聲明或者變量的聲明。對(duì)于聲明,此存儲(chǔ)類指定一個(gè) extern 對(duì)象聲明,即使該對(duì)象不存在,對(duì)于該聲明的引用也不會(huì)導(dǎo)致鏈接器對(duì)未解析的引用(找不到定義的引用)當(dāng)做錯(cuò)誤來(lái)處理。??如果「在當(dāng)前編譯單元中」可以找到 __weak 聲明定義,則會(huì)用找到的定義替換 __weak 引用;對(duì)于找不到定義 __weak 的聲明(函數(shù)或變量,如上圖的 FuncB),編譯器做如下處理:

引用被解析為分支連接指令 BL。等效于將被引用的分支為 NOP

直接將引用替換為 NOP 指令

注意:必須是在當(dāng)前編譯單元,不再當(dāng)前編譯單元的沒有意義(例如 ExtFuncA 在 main.c 中只有__weak 聲明,但是沒有定義)。具體看下圖的測(cè)試代碼:

bb9fc3d2-a862-11ed-bfe3-dac502259ad0.png

「注意:用 __weak 聲明然后不使用 __weak 定義的函數(shù)的行為相當(dāng)于非弱函數(shù)?!?這與 _attribute__((weak)) 關(guān)鍵字不同!

定義

用 __weak 定義的函數(shù)弱輸出其符號(hào)。弱定義的函數(shù)的行為類似于正常定義的函數(shù),除非將同名的非弱定義的函數(shù)鏈接到同一鏡像中。 如果在同一鏡像中同時(shí)存在非弱定義函數(shù)和弱定義函數(shù),則對(duì)該函數(shù)的所有調(diào)用都會(huì)解析為調(diào)用非弱函數(shù),否則直接使用弱定義的函數(shù)(與上面的若聲明不同)。??如果可以使用多個(gè)弱定義,則除非使用鏈接器選項(xiàng) --muldefweak,否則鏈接器會(huì)生成一條錯(cuò)誤消息。在這種情況下,鏈接器隨機(jī)選擇一個(gè)供所有調(diào)用來(lái)使用。使用方式如下:

/*a.h?。。∽⒁馑谖募煌。?!*/
voidFuncA(void);
voidFuncB(void);

/*a.c!?。∽⒁馑谖募煌。。?/
voidFuncA(void)
{
FuncB();/*這里將替換為main.c中的FuncB*/
}

__weakvoidFuncB(void)/*弱定義*/
{

}

/*main.c?。?!注意所在文件不同!??!*/
voidFuncB(void)
{

}

intmain(void)
{
FuncB();
}
12345678910111213141516171819202122232425

注意,函數(shù)的聲明一定不能添加 __weak 關(guān)鍵字。具體如下圖:bbede116-a862-11ed-bfe3-dac502259ad0.png

「注意:用 __weak 聲明然后不使用 __weak 定義的函數(shù)的行為相當(dāng)于非弱函數(shù)?!?這與 _attribute__((weak)) 關(guān)鍵字不同!

限制

函數(shù)或變量不能在同一編譯中同時(shí)弱和非弱地使用。

voidf(void);

voidg()
{
f();/*非弱函數(shù)引用*/
}

__weakvoidf(void);

voidh()
{
f();/*弱函數(shù)引用*/
}
12345678910111213

不能在定義函數(shù)或變量的同一編譯中使用弱函數(shù)或弱變量,如下將導(dǎo)致編譯錯(cuò)誤(正確的使用方式參考上面的使用示例):

/*a.c如下同一文件中的定義及使用將報(bào)錯(cuò)*/
__weakvoidf(void);

voidh()
{
f();
}

voidf()
{

}
123456789101112

弱函數(shù)不能是內(nèi)聯(lián)函數(shù)

「attribute」((weak))

__attribute__關(guān)鍵字使您可以指定變量或結(jié)構(gòu)字段,函數(shù)和類型的特殊屬性(與具體屬性)。該關(guān)鍵字的作用與 __weak 的作用基本是一樣的,在使用時(shí)有些不同,此外在某些情況下,編譯的處理也有些區(qū)別。

聲明

??這個(gè)參數(shù)是 GUN 編譯器的一個(gè)擴(kuò)展,ARM 編譯器也支持該關(guān)鍵字。__attribute__((weak)) 可以聲明弱變量,并且其聲明方式與 __weak 相比更加靈活。除了 __weak 的聲明方式,我們還可以用 extern int Variable_Attributes_weak_1 __attribute__((weak));??_attribute__((weak)) 可以聲明弱函數(shù),其聲明方式與 __weak 相比更加靈活。除了 __weak 的聲明方式,我們還可以用 extern int Function_Attributes_weak_0 (int b) __attribute__((weak));。

??任何包含了 __attribute__((weak)); 聲明的文件的中的同名函數(shù)定義,都將被當(dāng)做弱函數(shù)。如下圖:bc1bde90-a862-11ed-bfe3-dac502259ad0.png

開篇提出的問題就是因?yàn)樯蠄D所示的這種情況!

「注意:用 __attribute__((weak)) 聲明然后不使用 __attribute__((weak)) 進(jìn)行定義的函數(shù)的行為就像是弱函數(shù)?!?這與 __weak 關(guān)鍵字的用法不同。

在 GNU 模式中需要 extern 限定符。在非 gnu 模式下,編譯器假設(shè)如果變量不是 extern,那么它將像對(duì)待其他非弱變量一樣對(duì)待。

定義

用 __attribute__((weak)) 定義的函數(shù)弱輸出其符號(hào)(與 __weak 相同)。其使用方式有以下兩種:

__attribute__((weak))voidFuncA(void)
{
printf("WeakFuncA!
");
}
/*或者*/
void__attribute__((weak))FuncA(void)
{
printf("WeakFuncA!
");
}
123456789

「注意:用 __attribute__((weak)) 聲明然后不使用 __attribute__((weak)) 進(jìn)行定義的函數(shù)的行為就像是弱函數(shù)?!?這與 __weak 關(guān)鍵字的用法不同。除此之外,沒有啥不同,這里不再多說!

區(qū)別

如上介紹,__weak 和 __attribute__((weak)) 在聲明和定義的時(shí)候,其所處的位置有不同。

__weak 僅在函數(shù)定義中使用時(shí)才會(huì)生成弱函數(shù)。而在任何情況下(聲明和定義) __attribute__((weak)) 都會(huì)生成弱函數(shù),無(wú)論是用于函數(shù)定義還是用于函數(shù)聲明中!

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ARM
    ARM
    +關(guān)注

    關(guān)注

    134

    文章

    9094

    瀏覽量

    367538
  • GCC
    GCC
    +關(guān)注

    關(guān)注

    0

    文章

    107

    瀏覽量

    24841
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62604
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1634

    瀏覽量

    49129
  • 關(guān)鍵字
    +關(guān)注

    關(guān)注

    0

    文章

    37

    瀏覽量

    6895

原文標(biāo)題:__weak 和 __attribute__((weak)) 關(guān)鍵字的使用

文章出處:【微信號(hào):技術(shù)讓夢(mèng)想更偉大,微信公眾號(hào):技術(shù)讓夢(mèng)想更偉大】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    寫入FLASH的關(guān)鍵字

    求各位大神,我想寫一個(gè)數(shù)組,放有1024個(gè)數(shù),用的是430單片機(jī),RAM肯定放不下,有沒有這樣一個(gè)關(guān)鍵字,直接寫入FLASH,急?。。。。。?/div>
    發(fā)表于 08-15 22:07

    static 關(guān)鍵字

    static 關(guān)鍵字 淺析
    發(fā)表于 01-16 16:55

    嵌入式軟件編程關(guān)鍵字的用法和原理

    青島職業(yè)技術(shù)學(xué)院劉浩山東省文登市澤頭鎮(zhèn)***張斌引言計(jì)算機(jī)編程語(yǔ)言的關(guān)鍵字就好比是它的靈魂,只有深入理解了它們的含義才能編寫出優(yōu)秀的代碼。C語(yǔ)言以其簡(jiǎn)潔、高效和強(qiáng)大等特性成為嵌入式軟件編程的首選語(yǔ)言
    發(fā)表于 06-20 07:37

    【原創(chuàng)分享】單片機(jī)編程關(guān)鍵字之volatile

    k = i;//④語(yǔ)句volatile關(guān)鍵字告訴編譯器,i是隨時(shí)可能發(fā)生改變的。每次使用它的時(shí)候必須從內(nèi)存取出i的值,因而編譯器生成的匯編代碼會(huì)重新從i的地址處讀取數(shù)據(jù)放在k。這樣看來(lái),如果i
    發(fā)表于 06-29 11:17

    volatile關(guān)鍵字應(yīng)用場(chǎng)景及示例

    volatile關(guān)鍵字1.應(yīng)用場(chǎng)景2.示例1.應(yīng)用場(chǎng)景volatile關(guān)鍵字分析,往往應(yīng)用在三種場(chǎng)合1)多線程編程共享全局變量的時(shí)候,該全局變量要加上volatile進(jìn)行修飾,讓編譯器不要優(yōu)化該變量
    發(fā)表于 08-24 07:21

    關(guān)鍵字static的作用是什么

    頭文件的ifndef/define/endif 的作用?1.關(guān)鍵字static的作用是什么1). 在函數(shù)體,一個(gè)被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程維持其值不變。2). 在模塊內(nèi)(但在函數(shù)體外
    發(fā)表于 11-09 07:23

    C51關(guān)鍵字及用途說明

    C51 關(guān)鍵字關(guān)鍵字 用途 說明auto 存儲(chǔ)種類說明 用以說明局部變量,缺省值為此break 程序語(yǔ)句 退出最內(nèi)層循環(huán)case 程序語(yǔ)句 Switch 語(yǔ)句中的選擇項(xiàng)char 數(shù)據(jù)類型說明
    發(fā)表于 02-21 08:57 ?71次下載

    arduino關(guān)鍵字資料

    arduino關(guān)鍵字
    發(fā)表于 04-23 10:46 ?7次下載

    javastatic關(guān)鍵字的作用

    static關(guān)鍵字是很多朋友在編寫代碼和閱讀代碼時(shí)碰到的比較難以理解的一個(gè)關(guān)鍵字,也是各大公司的面試官喜歡在面試時(shí)問到的知識(shí)點(diǎn)之一。下面就先講述一下static關(guān)鍵字的用法和平常容易誤解的地方,最后
    發(fā)表于 09-27 17:12 ?0次下載

    java final關(guān)鍵字用法技巧匯總解析

    談到final關(guān)鍵字,想必很多人都不陌生,在使用匿名內(nèi)部類的時(shí)候可能會(huì)經(jīng)常用到final關(guān)鍵字。另外,Java的String類就是一個(gè)final類,那么今天我們就來(lái)了解final這個(gè)關(guān)鍵字
    發(fā)表于 12-01 11:02 ?1123次閱讀
    java final<b class='flag-5'>關(guān)鍵字</b>用法技巧匯總解析

    C++mutable關(guān)鍵字詳解與實(shí)戰(zhàn)

    mutable關(guān)鍵字詳解與實(shí)戰(zhàn) 在C++mutable關(guān)鍵字是為了突破const關(guān)鍵字的限制,被mutable關(guān)鍵字修飾的成員變量永遠(yuǎn)處于
    的頭像 發(fā)表于 09-10 09:23 ?5561次閱讀

    keilC51關(guān)鍵字code用法

    keil關(guān)鍵字code說明?用unsigned int 或signed char等定義的變量都存儲(chǔ)在單片機(jī)的RAM,程序可以隨意更改這些變量的值。而運(yùn)用code
    發(fā)表于 11-29 10:36 ?13次下載
    keil<b class='flag-5'>中</b>C51<b class='flag-5'>關(guān)鍵字</b>code用法

    const關(guān)鍵字應(yīng)用總結(jié)

    C++的const關(guān)鍵字的用法非常靈活,而使用const將大大改善程序的健壯性
    的頭像 發(fā)表于 05-26 09:06 ?574次閱讀

    this關(guān)鍵字在Java的用法

    this 關(guān)鍵字只能在方法內(nèi)部使用,表示對(duì)“調(diào)用方法的那個(gè)對(duì)象”的引用。 其實(shí)簡(jiǎn)單來(lái)說 this 關(guān)鍵字就是表示當(dāng)前對(duì)象,下面我們來(lái)具體介紹 this 關(guān)鍵字在Java
    的頭像 發(fā)表于 10-10 16:49 ?586次閱讀
    this<b class='flag-5'>關(guān)鍵字</b>在Java<b class='flag-5'>中</b>的用法

    快速掌握C語(yǔ)言關(guān)鍵字

    C語(yǔ)言中的32個(gè)關(guān)鍵字你知道多少個(gè)呢?根據(jù)關(guān)鍵字的作用分為四類:數(shù)據(jù)類型關(guān)鍵字、控制語(yǔ)句關(guān)鍵字、存儲(chǔ)類型關(guān)鍵字和其它
    的頭像 發(fā)表于 07-06 08:04 ?350次閱讀
    快速掌握C語(yǔ)言<b class='flag-5'>關(guān)鍵字</b>