淺談C/C++中的static和extern關(guān)鍵字

1 原理

1.1 首先,關(guān)于聲明和定義的區(qū)別。

這種寫法(函數(shù)原型后加;號(hào)表示結(jié)束的寫法)只能叫函數(shù)聲明而不能叫函數(shù)定義,只有帶函數(shù)體的聲明才叫定義,比如下面

只有分配存儲(chǔ)空間的變量聲明才叫變量定義,其實(shí)函數(shù)也是一樣,編譯器只有見到函數(shù)定義才會(huì)生成指令,而指令在程序運(yùn)行時(shí)當(dāng)然也要占存儲(chǔ)空間。那么沒有函數(shù)體的函數(shù)聲明有什么用呢?它為編譯器提供了有用的信息,編譯器在翻譯代碼的過程中,只有見到函數(shù)原型(不管帶不帶函數(shù)體)之后才知道這個(gè)函數(shù)的名字、參數(shù)類型和返回值,這樣碰到函數(shù)調(diào)用時(shí)才知道怎么生成相應(yīng)的指令,所以函數(shù)原型必須出現(xiàn)在函數(shù)調(diào)用之前,這也是遵循“先聲明后使用”的原則。

1.2 標(biāo)識(shí)符的鏈接屬性(Linkage)有三種

外部鏈接(ExternalLinkage)

如果最終的可執(zhí)行文件由多個(gè)程序文件鏈接而成,一個(gè)標(biāo)識(shí)符在任意程序文件中即使聲明多次也都代表同一個(gè)變量或函數(shù),則這個(gè)標(biāo)識(shí)符具有External Linkage。具有External Linkage的標(biāo)識(shí)符編譯后在符號(hào)表中是GLOBAL的符號(hào)。

內(nèi)部鏈接(InternalLinkage)

如果一個(gè)標(biāo)識(shí)符在某個(gè)程序文件中即使聲明多次也都代表同一個(gè)變量或函數(shù),則這個(gè)標(biāo)識(shí)符具有Internal Linkage。具有Internal Linkage的標(biāo)識(shí)符編譯后在符號(hào)表中是LOCAL的符號(hào)。

無鏈接(NoLinkage)

除以上情況之外的標(biāo)識(shí)符都屬于No Linkage的,例如函數(shù)的局部變量,以及不表示變量和函數(shù)的其它標(biāo)識(shí)符。

1.3 聲明和定義的次數(shù)限制

凡是被多次聲明的變量或函數(shù),必須有且只有一個(gè)聲明是定義,如果有多個(gè)定義,或者一個(gè)定義都沒有,鏈接器就無法完成鏈接。顯然,聲明可以有很多次。

2 用extern和static修飾函數(shù)

測(cè)試案例2.1

測(cè)試案例2.1結(jié)果

編譯不能通過,error C2129: 靜態(tài)函數(shù)“void print_03(void)”已聲明但未定義因?yàn)閜rint_03在extern_static_test1.h中被聲明為static。當(dāng)static修飾函數(shù)的時(shí)候,說明此函數(shù)只能被自己內(nèi)部的文件使用,即具有internal linkage.因此main不能調(diào)用extern_static_test1.h中被static修飾的函數(shù)。如有有這樣幾個(gè)文件a.h, a.cpp, main.cpp。其中a.h被a.cpp和main.cpp所包含,那么a.h中用static修飾的函數(shù)只能被a.cpp中的函數(shù)調(diào)用,不能被main.cpp中的函數(shù)調(diào)用.這個(gè)internal linkage屬性就被確定了。即使你故意在main.cpp中進(jìn)行一次external的聲明(如extern void print_03(void);)也不能改變此internal linkage鏈接屬性。

測(cè)試案例2.2

為了修正測(cè)試案例2.1的錯(cuò)誤,在main.cpp中刪除print_03();其它文件保持不變

則編譯沒有錯(cuò)誤了,運(yùn)行結(jié)果是,

測(cè)試案例2.2結(jié)果

1. ?print_02()說明,函數(shù)被聲明為external后,才能做到在多個(gè)文件中多次聲明的情況下,依然指示同一個(gè)定義。

2. ?print_01()說明,函數(shù)聲明如果不加external,也不加static,則默認(rèn)為external.

3.

print_04()說明,如果函數(shù)聲明使用了static修飾符,則這個(gè)函數(shù)具有internallinkage,只能被聲明所在的文件內(nèi)部調(diào)用。所以這里的print_04()調(diào)用了聲明為static的print_03()。print_04()不具有static屬性,所以在main.cpp中能夠被調(diào)用。

測(cè)試案例2.3

在main.cpp中強(qiáng)制用extern修飾符聲明print_03();其它文件保持不變會(huì)發(fā)生什么?

測(cè)試案例2.3結(jié)果

依然出現(xiàn)編譯錯(cuò)誤。說明,在a.h中已經(jīng)被聲明為static的文件,被main.cpp包含之后,main.cpp中不能修改它的屬性為external。

3 用extern和static修飾變量

測(cè)試案例3.1

由于是變量定義,所以不寫在extern_static_test1.h中,extern_static_test1.h和上文保持基本一致,為了簡(jiǎn)化,只保留了一個(gè)函數(shù)。

變量定義寫在了extern_static_test1.cpp中,如下

現(xiàn)在來看看main.cpp文件

測(cè)試案例3.1結(jié)果

編譯發(fā)現(xiàn),var1和var3都出現(xiàn)了編譯錯(cuò)誤。

這說明,雖然已經(jīng)在這里喪心病狂地對(duì)3個(gè)變量的生命都寫明了extern.

extern int var1;

extern int var2;

extern int var3

但是,因?yàn)樵趀xtern_static_test1.cpp的文件中,var3已經(jīng)被定義為了static,所以它具有internallinkage了,只能在extern_static_test1.cpp中被使用了,不能在main.cpp中被使用了;因?yàn)樵趀xtern_static_test1.cpp的文件中,var1沒有修飾符,變量如果沒有鏈接屬性的修飾符,默認(rèn)是static。這和函數(shù)正好相反,函數(shù)如果沒有鏈接屬性的修飾符,默認(rèn)是external。想想,這樣設(shè)定是符合實(shí)際需求的,函數(shù)就是用來進(jìn)行操作,被調(diào)用的,默認(rèn)external更方便,變量不應(yīng)該被隨意使用,而應(yīng)該被函數(shù)操作,這樣才安全。

main.cpp修改之后,正確

測(cè)試案例3.2

如果把main.cpp中external聲明的關(guān)鍵字external去掉,extern_static_test1.h和extern_static_test1.cpp保持不變,這樣是否正確呢?

測(cè)試案例3.2結(jié)果

出現(xiàn)編譯錯(cuò)誤,說明,如果要使得一個(gè)變量具有external linkage,必須在定義時(shí)和聲明時(shí)都得加上external修飾符,比如這里需要在extern_static_test1.cpp中var2的定義和main.cpp中的var2的聲明中都寫上external修飾符。因?yàn)樽兞磕J(rèn)是static,你要不特別說明它是external,那就默認(rèn)是static了。



二者的一些定性說明:

static:

一、在C中,static主要定義全局靜態(tài)變量、定義局部靜態(tài)變量、定義靜態(tài)函數(shù)。

1、定義全局靜態(tài)變量:在全局變量前面加上關(guān)鍵字static,該全局變量變成了全局靜態(tài)變量。全局靜態(tài)變量有以下特點(diǎn)。

???????????? a.在全局區(qū)分配內(nèi)存。

?????????? ? b.如果沒有初始化,其默認(rèn)值為0.

????????? ? c.該變量在本文件內(nèi)從定義開始到文件結(jié)束可見。

2、定義局部靜態(tài)變量:在局部變量前面加上關(guān)鍵字static,其特點(diǎn)如下:

???????????? a.該變量在全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存。

??????????? b.它始終駐留在全局?jǐn)?shù)據(jù)區(qū),直到程序運(yùn)行結(jié)束。

??????????? c. 其作用域?yàn)榫植孔饔糜颍?dāng)定義它的函數(shù)或語句塊結(jié)束時(shí),其作用域隨之結(jié)束。

3、定義靜態(tài)函數(shù):在函數(shù)返回類型前加上static關(guān)鍵字,函數(shù)即被定義為靜態(tài)函數(shù),其特點(diǎn)如下:

???????????? a.靜態(tài)函數(shù)只能在本源文件中使用

????????????? b.在文件作用域中聲明的inline函數(shù)默認(rèn)為static類型

二、在C++中新增了兩種作用:定義靜態(tài)數(shù)據(jù)成員或靜態(tài)函數(shù)成員。

定義靜態(tài)數(shù)據(jù)成員。

????? ? ? ? ? a.內(nèi)存分配:靜態(tài)數(shù)據(jù)成員在程序的全局?jǐn)?shù)據(jù)區(qū)分配。

????? ? ? ?? ? b.初始化和定義:靜態(tài)數(shù)據(jù)成員定義時(shí)要分配空間,所以不能在類聲明中定義。

????????? 靜態(tài)數(shù)據(jù)成員因?yàn)槌绦蛞蚤_始運(yùn)行就必須存在,所以其初始化的最佳位置在類的內(nèi)部,public、protected、private關(guān)鍵字對(duì)它的限定和普通數(shù)據(jù)成員一樣,因?yàn)槠淇臻g在全局?jǐn)?shù)據(jù)分配,屬于所有本類的對(duì)象共享。它不屬于特定的類對(duì)象,在沒產(chǎn)生類對(duì)象時(shí),其作用域可見,即沒有產(chǎn)生類的實(shí)例時(shí),就可以操作它了。

靜態(tài)成員函數(shù)。靜態(tài)成員函數(shù)與類相聯(lián)系,不與類的對(duì)象相聯(lián)系。靜態(tài)成員函數(shù)不能訪問非靜態(tài)數(shù)據(jù)成員。

extern:

extern可以置于變量或函數(shù)前,以在別的文件中標(biāo)識(shí)變量或函數(shù)的定義,并提示編譯器遇到此變量或函數(shù)時(shí)在其他模塊中尋找其定義。extern是C、C++語言中表明函數(shù)和全局變量作用范圍(可見性)的關(guān)鍵字。對(duì)于extern變量來說,僅僅是一個(gè)變量的聲明,其并不是定義,不會(huì)分配內(nèi)存空間。extern表示將變量或函數(shù)聲明為外部鏈接,變量默認(rèn)是內(nèi)部鏈接,函數(shù)默認(rèn)是外部鏈接。因此用來外部鏈接的函數(shù),聲明時(shí)有無extern都可以連接通過。而全局變量則不行。通常,在模塊的頭文件中,對(duì)本模塊提供給其他模塊引用的函數(shù)和全局變量以關(guān)鍵字extern聲明。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,214評(píng)論 3 426
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,781評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,315評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,699評(píng)論 1 327
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,882評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,441評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,189評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,388評(píng)論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,613評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評(píng)論 1 293
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,112評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,334評(píng)論 2 377

推薦閱讀更多精彩內(nèi)容

  • C++關(guān)鍵字的思考 本章內(nèi)容:1 關(guān)鍵字的相關(guān)理解1.1 const關(guān)鍵字1.2 static關(guān)鍵字1.3 非局部...
    Haley_2013閱讀 783評(píng)論 0 50
  • C++的static有兩種用法:面向過程程序設(shè)計(jì)中的static和面向?qū)ο蟪绦蛟O(shè)計(jì)中的static。前者應(yīng)用于普通...
    yangqi916閱讀 397評(píng)論 0 0
  • 總有那么一個(gè)時(shí)刻,你的耳機(jī)中會(huì)單曲循環(huán)著一首歌,說不出為什么,就是覺得那個(gè)時(shí)間,那首歌剛剛好。 許久不曾寫文章,手...
    周詩汶閱讀 356評(píng)論 0 0
  • 我慶幸我厚顏無恥,不斷的擺弄我那不堪入目的文字,展示我自以為的學(xué)富五車。我慶幸的是,我能把我的情緒寫出來,讓別人知...
    沐府墓主閱讀 192評(píng)論 0 1
  • 畢業(yè),這兩個(gè)字意味著責(zé)任與擔(dān)當(dāng)。此刻面臨畢業(yè)的我們,想得不再是今天逃課還好沒被老師發(fā)現(xiàn);期末考試一定要左右逢源,天...
    38f9fa77010c閱讀 275評(píng)論 0 1