<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>
"); //-->

博客專(zhuān)欄

EEPW首頁(yè) > 博客 > C語(yǔ)言進(jìn)階小技巧,弱符號和弱引用

C語(yǔ)言進(jìn)階小技巧,弱符號和弱引用

發(fā)布人:xiaomaidashu 時(shí)間:2022-07-18 來(lái)源:工程師 發(fā)布文章

__attribute__ 是一個(gè)編譯器指令,其實(shí)是 GNU C 的一種機制,本質(zhì)是一個(gè)編譯器的指令,在聲明的時(shí)候可以提供一些屬性,在編譯階段起作用,來(lái)做多樣化的錯誤檢查和高級優(yōu)化。

用于在 C,C++,Objective-C 中修飾變量、函數、參數、方法、類(lèi)等。

合理使用 __attribute__ 有什么好處?
  • 給編譯器提供上下文,幫助編譯器做優(yōu)化,合理使用可以收到顯著(zhù)的優(yōu)化效果。
  • 編譯器會(huì )根據 __attribute__ 產(chǎn)生一些編譯警告,使代碼更規范。
  • 給代碼閱讀者提供必要的注解,助其理解代碼意圖。

總之,__attribute__ 起到了給編譯器提供上下文的作用,如果錯誤的使用 __attribute__ 指令,因為給編譯器提供了錯誤的上下文,由此引起的錯誤通常很難被發(fā)現。

強符號和弱符號

在同一作用域下不能定義同一個(gè)變量或函數,很多C語(yǔ)言學(xué)習者都理所當然地這么認為。

這個(gè)其實(shí)是是有所偏頗的,GNU C對標準C語(yǔ)言進(jìn)行了擴展,在GCC中,對于符號(在編譯時(shí),變量和函數都被抽象成符號)而言,存在著(zhù)強符號和弱符號之分。

是的,是否支持這個(gè)特性是由不同的C語(yǔ)言標準決定的。

對于C/C++而言,編譯器默認函數和已初始化的全局變量為強符號,而未初始化的全局變量為弱符號。

在編程者沒(méi)有顯示指定時(shí),編譯器對強弱符號的定義會(huì )有一些默認行為,同時(shí)開(kāi)發(fā)者也可以對符號進(jìn)行指定,使用"attribute((weak))"來(lái)聲明一個(gè)符號為弱符號。

定義一個(gè)相同的變量,當兩者不全是強符號時(shí),gcc在編譯時(shí)并不會(huì )報錯,而是遵循一定的規則進(jìn)行取舍:

  • 當兩者都為強符號時(shí),重復定義的報錯:redefinition of 'xxx'
  • 當兩者為一強一弱時(shí),選取強符號的值
  • 當兩者同時(shí)為弱時(shí),選擇其中占用空間較大的符號,這個(gè)其實(shí)很好理解,編譯器不知道編程者的用意,選擇占用空間大的符號至少不會(huì )造成諸如溢出、越界等嚴重后果。

在默認的符號類(lèi)型情況下,強符號和弱符號是可以共存的,類(lèi)似于這樣:

int x;
int x = 1;

編譯不會(huì )報錯,在編譯時(shí)x的取值將會(huì )是1.

注意,這里可以使用__attribute__((weak))將強符號轉換為弱符號,卻不能與一個(gè)強符號共存,類(lèi)似于這樣:

int __attribute__((weak)) x = 0;
int x = 1;

編譯器將報重復定義錯誤。

強引用和弱引用

除了強符號和弱符號的區別之外,GNUC還有一個(gè)特性就是強引用和弱引用。

我們知道的是,編譯器在編譯階段只負責將源文件編譯成目標文件(即二進(jìn)制文件),然后由鏈接器對所有二進(jìn)制文件進(jìn)行鏈接操作。

編譯器默認所有的變量和函數為強引用,同時(shí)編程者可以使用__attribute__((weakref))來(lái)聲明一個(gè)函數。

注意這里是聲明而不是定義,既然是引用,那么就是使用其他模塊中定義的實(shí)體,對于函數而言,我們可以使用這樣的寫(xiě)法:

__attribute__((weakref)) void func(void);

,然后在函數中調用func(),如果func()沒(méi)有被定義,則func的值為0,如果func被定義,則調用相應func,在《程序員的自我修養》這本書(shū)中有介紹,它是這樣寫(xiě)的:

__attribute__((weakref)) void func(void);
void main(void)
{
    if(func) {func();}
}

但是在現代的編譯系統中,這種寫(xiě)法卻是錯誤的,編譯雖然通過(guò)(有警告信息),但是卻不正確:

warning: ‘weakref’ attribute should be accompanied with an ‘alias’ attribute [-Wattributes]

警告顯示:weakref需要伴隨著(zhù)一個(gè)別名才能正常使用

強/弱符號和強/弱引用的作用

這種弱符號、弱引用的擴展機制在庫的實(shí)現中非常有用。

我們在庫中可以使用弱符號和弱引用機制,這樣對于一個(gè)弱符號函數而言,用戶(hù)可以自定義擴展功能的函數來(lái)覆蓋這個(gè)弱符號函數。

同時(shí)我們可以將某些擴展功能函數定義為弱引用,當用戶(hù)需要使用擴展功能時(shí),就對其進(jìn)行定義,鏈接到程序當中。

如果用戶(hù)不進(jìn)行定義,則鏈接也不會(huì )報錯,這使得庫的功能可以很方便地進(jìn)行裁剪和組合。

注意:C標準里根本沒(méi)有提到強、弱符號。這只是GCC這個(gè)實(shí)現定義的特性,在MS C編譯器里是不存在這個(gè)概念的。


*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。



關(guān)鍵詞: C語(yǔ)言

相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>