博客專欄

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

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

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

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

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

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

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

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

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

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

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

        對(duì)于C/C++而言,編譯器默認(rèn)函數(shù)和已初始化的全局變量為強(qiáng)符號(hào),而未初始化的全局變量為弱符號(hào)。

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

        定義一個(gè)相同的變量,當(dāng)兩者不全是強(qiáng)符號(hào)時(shí),gcc在編譯時(shí)并不會(huì)報(bào)錯(cuò),而是遵循一定的規(guī)則進(jìn)行取舍:

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

        在默認(rèn)的符號(hào)類型情況下,強(qiáng)符號(hào)和弱符號(hào)是可以共存的,類似于這樣:

        int x;
        int x = 1;

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

        注意,這里可以使用__attribute__((weak))將強(qiáng)符號(hào)轉(zhuǎn)換為弱符號(hào),卻不能與一個(gè)強(qiáng)符號(hào)共存,類似于這樣:

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

        編譯器將報(bào)重復(fù)定義錯(cuò)誤。

        強(qiáng)引用和弱引用

        除了強(qiáng)符號(hào)和弱符號(hào)的區(qū)別之外,GNUC還有一個(gè)特性就是強(qiáng)引用和弱引用。

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

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

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

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

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

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

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

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

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

        強(qiáng)/弱符號(hào)和強(qiáng)/弱引用的作用

        這種弱符號(hào)、弱引用的擴(kuò)展機(jī)制在庫(kù)的實(shí)現(xiàn)中非常有用。

        我們?cè)趲?kù)中可以使用弱符號(hào)和弱引用機(jī)制,這樣對(duì)于一個(gè)弱符號(hào)函數(shù)而言,用戶可以自定義擴(kuò)展功能的函數(shù)來(lái)覆蓋這個(gè)弱符號(hào)函數(shù)。

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

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

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


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



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

        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 揭东县| 崇阳县| 星子县| 巴楚县| 玛纳斯县| 越西县| 磴口县| 新丰县| 错那县| 务川| 山西省| 天水市| 磴口县| 芜湖县| 阿鲁科尔沁旗| 谢通门县| 大化| 通海县| 商南县| 山阳县| 嵩明县| 洛隆县| 陇南市| 株洲市| 武清区| 定西市| 汤阴县| 孟连| 彝良县| 凌海市| 孝感市| 长治县| 四川省| 满城县| 资源县| 行唐县| 鄂尔多斯市| 当雄县| 丰宁| 深泽县| 鸡泽县|