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

1 原理

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

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

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

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

外部鏈接(ExternalLinkage)

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

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

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

無鏈接(NoLinkage)

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

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

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

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

測試案例2.1

測試案例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鏈接屬性。

測試案例2.2

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

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

測試案例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)用秒旋。

測試案例2.3

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

測試案例2.3結(jié)果

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

3 用extern和static修飾變量

測試案例3.1

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

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

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

測試案例3.1結(jié)果

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

這說明,雖然已經(jīng)在這里喪心病狂地對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修改之后滔驾,正確

測試案例3.2

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

測試案例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)鍵字對它的限定和普通數(shù)據(jù)成員一樣,因?yàn)槠淇臻g在全局?jǐn)?shù)據(jù)分配螟加,屬于所有本類的對象共享徘溢。它不屬于特定的類對象,在沒產(chǎn)生類對象時(shí)捆探,其作用域可見然爆,即沒有產(chǎn)生類的實(shí)例時(shí),就可以操作它了徐许。

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

extern:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涂屁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子灰伟,更是在濱河造成了極大的恐慌拆又,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袱箱,死亡現(xiàn)場離奇詭異遏乔,居然都是意外死亡狼钮,警方通過查閱死者的電腦和手機(jī)赫编,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門冰单,熙熙樓的掌柜王于貴愁眉苦臉地迎上來艇炎,“玉大人蜗帜,你說我怎么就攤上這事橡伞《耆ⅲ” “怎么了敦腔?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵前计,是天一觀的道長胞谭。 經(jīng)常有香客問我,道長男杈,這世上最難降的妖魔是什么丈屹? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上旺垒,老公的妹妹穿的比我還像新娘彩库。我一直安慰自己,他們只是感情好先蒋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竞漾,像睡著了一般眯搭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上业岁,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音叨襟,去河邊找鬼繁扎。 笑死幔荒,一個(gè)胖子當(dāng)著我的面吹牛糊闽,可吹牛的內(nèi)容都是我干的爹梁。 我是一名探鬼主播右犹,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼姚垃!你這毒婦竟也來了念链?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤积糯,失蹤者是張志新(化名)和其女友劉穎掂墓,沒想到半個(gè)月后看成,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體君编,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年川慌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梦重。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡兑燥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出琴拧,到底是詐尸還是另有隱情降瞳,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布蚓胸,位于F島的核電站挣饥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏亮靴。R本人自食惡果不足惜馍盟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茧吊。 院中可真熱鬧贞岭,春花似錦搓侄、人聲如沸瞄桨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芯侥。三九已至乳讥,卻和暖如春柱查,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背云石。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工唉工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汹忠,地道東北人淋硝。 一個(gè)月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像宽菜,于是被迫代替她去往敵國和親谣膳。 傳聞我的和親對象是個(gè)殘疾皇子铅乡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(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閱讀 774評論 0 50
  • C++的static有兩種用法:面向過程程序設(shè)計(jì)中的static和面向?qū)ο蟪绦蛟O(shè)計(jì)中的static继谚。前者應(yīng)用于普通...
    yangqi916閱讀 391評論 0 0
  • 總有那么一個(gè)時(shí)刻,你的耳機(jī)中會單曲循環(huán)著一首歌隆判,說不出為什么,就是覺得那個(gè)時(shí)間侨嘀,那首歌剛剛好臭挽。 許久不曾寫文章,手...
    周詩汶閱讀 331評論 0 0
  • 我慶幸我厚顏無恥咬腕,不斷的擺弄我那不堪入目的文字欢峰,展示我自以為的學(xué)富五車。我慶幸的是纽帖,我能把我的情緒寫出來宠漩,讓別人知...
    沐府墓主閱讀 181評論 0 1
  • 畢業(yè),這兩個(gè)字意味著責(zé)任與擔(dān)當(dāng)懊直。此刻面臨畢業(yè)的我們,想得不再是今天逃課還好沒被老師發(fā)現(xiàn)室囊;期末考試一定要左右逢源雕崩,天...
    38f9fa77010c閱讀 267評論 0 1