欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談C語(yǔ)言中的強(qiáng)符號(hào)、弱符號(hào)、強(qiáng)引用和弱引用

 更新時(shí)間:2014年10月31日 09:02:15   投稿:hebedich  
這篇文章主要介紹了C語(yǔ)言中的強(qiáng)符號(hào)、弱符號(hào)、強(qiáng)引用和弱引用的定義及相關(guān)內(nèi)容,非常的簡(jiǎn)單易懂,有需要的朋友可以參考下

首先我表示很悲劇,在看《程序員的自我修養(yǎng)--鏈接、裝載與庫(kù)》之前我竟不知道C有強(qiáng)符號(hào)、弱符號(hào)、強(qiáng)引用和弱引用。在看到3.5.5節(jié)弱符號(hào)和強(qiáng)符號(hào)時(shí),我感覺(jué)有些困惑,所以寫(xiě)下此篇,希望能和同樣感覺(jué)的朋友交流也希望高人指點(diǎn)。

  首先我們看一下書(shū)中關(guān)于它們的定義。

  引入場(chǎng)景:(1)文件A中定義并初始化變量i(int i = 1), 文件B中定義并初始化變量i(int i = 2)。編譯鏈接A、B時(shí)會(huì)報(bào)錯(cuò)b.o:(.data+0x0): multiple definition of `i';a.o:(.data+0x0): multiple definition of `i'。(2)在文件C中定義并初始化兩個(gè)變量i(int i = 1; int i = 2), 編譯鏈接時(shí)會(huì)報(bào)錯(cuò)c.c:2:5: error: redefinition of ‘i'; c.c:1:5: note: previous definition of ‘i' was here。

  強(qiáng)符號(hào):像場(chǎng)景中這樣的符號(hào)定義被稱為強(qiáng)符號(hào),對(duì)于C/C++來(lái)說(shuō),編譯器默認(rèn)函數(shù)和初始化的全局變量為強(qiáng)符號(hào)。
  弱符號(hào):接上文,為初始化的全局變量為弱符號(hào)。
  編譯器關(guān)于強(qiáng)弱符號(hào)的規(guī)則有:(1)強(qiáng)符號(hào)不允許多次定義,但強(qiáng)弱可以共存;(2)強(qiáng)弱共存時(shí),強(qiáng)覆蓋弱;(3)都是弱符號(hào)時(shí),選擇占用空間最大的,如選擇  double類型的而不選擇int類型的。

  由以上定義所以有我之前沒(méi)有想到的場(chǎng)景:
  代碼a.c:

1 int i = 2;
  代碼b.c:

復(fù)制代碼 代碼如下:

#include<stdio.h>

int i;
int main(int argc, char** argv)
{
      printf("i = %d\n", i);
      return 0;     
}

  編譯文件a和b并鏈接,結(jié)果輸出i為2而不是0。
  并且在同一個(gè)文件中定義但未初始化兩個(gè)相同的變量不會(huì)報(bào)錯(cuò),只有在使用變量時(shí)才會(huì)報(bào)錯(cuò)。
  對(duì)于GCC編譯器來(lái)說(shuō),還允許使用__attribute__((weak))來(lái)將強(qiáng)符號(hào)定義為弱符號(hào),所已有
  代碼c.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
  __attribute__((weak)) int i = 1;
 
  int main(int argc, char** argv)
  {
       printf("i = %d\n", i);
       return 0;  
  }

  結(jié)果i的輸出仍未2而不是1。

  那么對(duì)于函數(shù)而言是不是也這樣呢?先不看函數(shù),而是先看由強(qiáng)弱符號(hào)而進(jìn)一步引入的強(qiáng)弱引用。書(shū)中關(guān)于強(qiáng)弱引用的概述是對(duì)于強(qiáng)引用若未定義則鏈接時(shí)肯定會(huì)報(bào)錯(cuò),而對(duì)于弱引用則不會(huì)報(bào)錯(cuò),鏈接器默認(rèn)其為0(這一點(diǎn)對(duì)于函數(shù)好理解,即函數(shù)符號(hào)所代表入口地址為0;對(duì)于變量就要注意了,既然是引用那自然就是地址了,所以同函數(shù)一樣變量的地址為0而不是變量的值為0)。此時(shí)對(duì)于強(qiáng)弱引用是不是還沒(méi)有什么明確的概念呢?到底什么是引用?引用和符號(hào)又是什么關(guān)系?這里我說(shuō)一下我的理解(歡迎指正),在定義和聲明處指定的函數(shù)名、變量名即為對(duì)應(yīng)的符號(hào),而在代碼其他處調(diào)用函數(shù)或使用變量時(shí),則把函說(shuō)明和變量名看作引用,這樣一來(lái)符號(hào)和引用在代碼層面上其實(shí)就是一個(gè)東西,只是根據(jù)環(huán)境而叫法不同而已。那么強(qiáng)符號(hào)對(duì)應(yīng)強(qiáng)引用,弱符號(hào)對(duì)應(yīng)弱引用。

  有上面的強(qiáng)弱引用的特點(diǎn)可看出,當(dāng)一個(gè)函數(shù)為弱引用時(shí),不管這個(gè)函數(shù)有沒(méi)有定義,鏈接時(shí)都不會(huì)報(bào)錯(cuò),而且我們可以根據(jù)判斷函數(shù)名是否為0來(lái)決定是否執(zhí)行這個(gè)函數(shù)。這樣一來(lái),包含這些函數(shù)的庫(kù)就可以以模塊、插件的形式和我們的引用組合一起,方便使用和卸載,并且由于強(qiáng)符號(hào)可以覆蓋弱符號(hào)和強(qiáng)弱符號(hào)與強(qiáng)弱引用的關(guān)系可知,我們自己定義函數(shù)可以覆蓋庫(kù)中的函數(shù),多么美妙。

  先看根據(jù)條件判斷是否執(zhí)行函數(shù):
  代碼d.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
void func()
{
     printf("func()#1\n");
}

  代碼e.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
 __attribute__((weak)) void func();
 
 int main(int argc, char** argv)
 {
      if (func)
          func();
      return 0;
 }

  編譯d.c,cc -c d.c 輸出d.o;編譯e.c并鏈接d.o,cc d.o e.c -o e輸出可執(zhí)行文件e,運(yùn)行e正常執(zhí)行函數(shù)func。編譯e.c但不鏈接d.o,此時(shí)并不會(huì)報(bào)錯(cuò),只不過(guò)func不會(huì)執(zhí)行,因?yàn)闆](méi)有它的定義所以if(func)為假。
  再看函數(shù)覆蓋:
  代碼f.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
 __attribute__((weak)) void func()
 {
      printf("func()#1\n");
 }

  代碼g.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
 void func()
 {
      printf("func()#2\n");
  }
 
 int main(int argc, char** argv)
 {
      func();
      return 0;
 }
 ~      

  編譯鏈接,結(jié)構(gòu)輸出"func()#2"。

  以上可以說(shuō)明函數(shù)和變量是保持一致的,其實(shí)對(duì)應(yīng)變量也可以像使用函數(shù)那樣先判斷再使用,只不過(guò)不是判斷變量的值而是變量的地址,如
  代碼v1.c

復(fù)制代碼 代碼如下:

int i = 2;

  代碼v2.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
 __attribute__((weak)) extern int i;
 
 int main(int argc, char** argv)
 {
      if (&i)
          printf("i = %d\n", i);
     return 0;
 }
 ~      

  編譯并鏈接v1時(shí),輸出2;編譯但不鏈接v1時(shí)無(wú)輸出。這樣做時(shí)要分清定義和聲明的區(qū)別,__attribute__((weak)) int i 是定義變量并轉(zhuǎn)換為弱符號(hào),這樣i是分配了空間的,而__attribute__((weak)) extern int i 則將原來(lái)定義的變量i由強(qiáng)符號(hào)轉(zhuǎn)換為弱符號(hào),導(dǎo)致使用i時(shí)不是強(qiáng)引用而是弱引用。不過(guò)雖然變量可以這么做但沒(méi)有函數(shù)那樣有意義。

  上面關(guān)于強(qiáng)弱引用仍舊使用的是GCC提供的__attribute__((weak)),而書(shū)中還提到了__attribute__((weakref)),后者貌似更能體現(xiàn)“引用”這一關(guān)鍵詞。而我之所以使用前者來(lái)介紹強(qiáng)弱引用,是因?yàn)槲覍?duì)關(guān)于強(qiáng)弱符號(hào)與強(qiáng)弱引用對(duì)應(yīng)關(guān)系的理解。關(guān)于__attribute__((weakref))的使用方法,這里介紹一種(兩者都有不同的使用方法)。
  代碼a.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
 void bar()
 {
      printf("foo()\n");
 }

  代碼b.c

復(fù)制代碼 代碼如下:

 #include<stdio.h>
 
 static void foo() __attribute__((weakref("bar")));
 
  int main(int argc, char** argv)
 {
      if (foo)
         foo();
 
      return 0;
 }

  注意函數(shù)foo的static修飾符,沒(méi)有的話會(huì)報(bào)錯(cuò),這樣將函數(shù)foo限制在只有本文件內(nèi)可使用。

  好了,夜已深,寫(xiě)的有點(diǎn)凌亂,我也凌亂了。

相關(guān)文章

  • C語(yǔ)言數(shù)組超詳細(xì)講解中篇三子棋

    C語(yǔ)言數(shù)組超詳細(xì)講解中篇三子棋

    數(shù)組是一組有序的數(shù)據(jù)的集合,本篇將帶你結(jié)合數(shù)組來(lái)實(shí)現(xiàn)三子棋小游戲,上手實(shí)練更快的能夠掌握數(shù)組使用,感興趣的朋友來(lái)看看吧
    2022-04-04
  • C++實(shí)現(xiàn)單鏈表刪除倒數(shù)第k個(gè)節(jié)點(diǎn)的方法

    C++實(shí)現(xiàn)單鏈表刪除倒數(shù)第k個(gè)節(jié)點(diǎn)的方法

    這篇文章主要介紹了C++實(shí)現(xiàn)單鏈表刪除倒數(shù)第k個(gè)節(jié)點(diǎn)的方法,結(jié)合實(shí)例形式分析了C++單鏈表的定義、遍歷及刪除相關(guān)操作技巧,需要的朋友可以參考下
    2017-05-05
  • C語(yǔ)言二叉樹(shù)的三種遍歷方式的實(shí)現(xiàn)及原理

    C語(yǔ)言二叉樹(shù)的三種遍歷方式的實(shí)現(xiàn)及原理

    這篇文章主要介紹了C語(yǔ)言二叉樹(shù)的三種遍歷方式的實(shí)現(xiàn)及原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • c++友元函數(shù)與友元類的深入解析

    c++友元函數(shù)與友元類的深入解析

    友元函數(shù)的特點(diǎn)是能夠訪問(wèn)類中的私有成員的非成員函數(shù)。友元函數(shù)從語(yǔ)法上看,它與普通函數(shù)一樣,即在定義上和調(diào)用上與普通函數(shù)一樣
    2013-07-07
  • C++超詳細(xì)講解函數(shù)重載

    C++超詳細(xì)講解函數(shù)重載

    C++ 允許多個(gè)函數(shù)擁有相同的名字,只要它們的參數(shù)列表不同就可以,這就是函數(shù)的重載(Function Overloading),借助重載,一個(gè)函數(shù)名可以有多種用途
    2022-05-05
  • C語(yǔ)言的合法標(biāo)識(shí)符與整型詳解

    C語(yǔ)言的合法標(biāo)識(shí)符與整型詳解

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的合法標(biāo)識(shí)符與整,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • 一文帶你搞懂C語(yǔ)言預(yù)處理宏定義

    一文帶你搞懂C語(yǔ)言預(yù)處理宏定義

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言預(yù)處理宏定義#define,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-10-10
  • C++對(duì)象的動(dòng)態(tài)建立與釋放詳解

    C++對(duì)象的動(dòng)態(tài)建立與釋放詳解

    我們知道可以用new運(yùn)算符可以動(dòng)態(tài)的分配內(nèi)存,用delete運(yùn)算符可以釋放這些內(nèi)存。當(dāng)我們使用new運(yùn)算符動(dòng)態(tài)的分配一個(gè)內(nèi)存之后,會(huì)自動(dòng)返回一個(gè)該內(nèi)存段的起始地址,也就是指針。
    2013-10-10
  • C++面試題之進(jìn)制轉(zhuǎn)換的實(shí)例

    C++面試題之進(jìn)制轉(zhuǎn)換的實(shí)例

    這篇文章主要介紹了C++面試題之進(jìn)制轉(zhuǎn)換的實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解掌握這樣的知識(shí),需要的朋友可以參考下
    2017-10-10
  • gdb調(diào)試的簡(jiǎn)單操作總結(jié)

    gdb調(diào)試的簡(jiǎn)單操作總結(jié)

    gdb是一個(gè)命令行下的、功能強(qiáng)大的調(diào)試器,這篇文章主要為大家詳細(xì)介紹了gdb?調(diào)試的一些簡(jiǎn)單操作,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-08-08

最新評(píng)論