C++ 全局變量鏈接性钉答、extern、static關(guān)鍵字

單定義原則杈抢、外部變量與extern

??C++有“單定義原則(One Definition Rule, ODR)”, 該規(guī)則決定了任何變量都只能有一次定義数尿。為了實(shí)現(xiàn)這種需求,C++提供了兩種變量聲明惶楼。一種是定義聲明(definition declaration),或者簡稱為定義(definition)右蹦,它給變量分配存儲(chǔ)空間;另外一種是引用聲明(referencing declaration)歼捐,或者簡稱為聲明(declaration)何陆,它不給變量分配存儲(chǔ)空間,因?yàn)樗靡延械淖兞俊?br> ??C++中引用聲明使用的關(guān)鍵字是"extern"窥岩,并且不進(jìn)行初始化甲献,否則,聲明將變成定義颂翼,編譯器會(huì)給該變量分配存儲(chǔ)空間晃洒。
??extern主要針對(duì)具有多個(gè)源文件的項(xiàng)目慨灭。如果有多個(gè)源文件需要使用到相同的全局變量,則這些變量只需要在其中的某一個(gè)源文件中定義一次球及,其它的源文件如果想使用這些外部變量氧骤,需要在聲明的時(shí)候前面加上"extern"。

//file01.cpp
extern int cats = 20; // 對(duì)cat定義
int dogs 22; // 定義dogs
int fleas; // 定義fleas
…

//file02.cpp
//use cat and dogs from file01.cpp
extern int cats; // 無需定義吃引,直接使用外部變量
extern int dogs;
extern int fleas;
…

??從上面這段代碼中可以看出筹陵,在定義變量的時(shí)候,關(guān)鍵字extern并不是必須的镊尺,但是朦佩,如果想聲明外部變量,則extern關(guān)鍵字是必不可少的庐氮。

單定義原則(ODR)≠ 不允許存在同名變量

??計(jì)算機(jī)識(shí)別變量依靠的是地址(務(wù)必記住這句話语稠,只要是地址不一樣,即使它們的名字相同弄砍,計(jì)算機(jī)也會(huì)認(rèn)為它們是不同的變量)仙畦,全局變量和靜態(tài)變量存儲(chǔ)在靜態(tài)區(qū),而函數(shù)中聲明音婶、定義的變量則存儲(chǔ)在棧區(qū)慨畸。不同函數(shù)之間聲明的同名自動(dòng)變量是彼此獨(dú)立的。但是衣式,對(duì)于每個(gè)“變量”寸士,程序中僅允許定義一次,服從ODR瞳收。
??此外碉京,如果在函數(shù)的內(nèi)部聲明、定義一個(gè)與全局變量同名同類型的自動(dòng)變量螟深,那么該變量的值會(huì)覆蓋原來的全局變量谐宙。以下程序?qū)Υ擞幸粋€(gè)較好的詮釋。

//external.cpp
// author: pengqi
// date: 2020/03/02
// reference: C++ Primer Plus P312
#include<iostream>
using namespace std;
// external warming
double warming = 1.7; // define warming

void update(double dt);
void local();

int main() {
   cout << "Global warming is " << warming << endl;
   update(1.1);
   cout << "Global warming is " << warming << endl;
   local();
   cout << "Global warming is " << warming << endl;
   return 0;
}

------------------
//external.cpp
// author: pengqi
// date: 2020/03/02
// reference: C++ Primer Plus P312
#include<iostream>
extern double warming; // Using the external warming

void update();
void local();

using std::cout;
void update(double dt) {
   warming = dt;
}

void local() {
    double warming = 0.5;
    cout << "Local warming is " << warming << std::endl;
    cout << "However, Global warming is " << ::warming << std::endl;
}

??程序運(yùn)行的輸出:

$ g++ external.cpp support.cpp -o extern_test
$ ./extern_test
Global warming is 1.7
Global warming is 1.1
Local warming is 0.5
However, Global warming is 1.1
Global warming is 1.1

??從上面程序的運(yùn)行結(jié)果中可以看出界弧,函數(shù)local同樣聲明了一個(gè)名為warming的變量凡蜻,這時(shí),在函數(shù)內(nèi)部垢箕,warming的值使用的是新聲明的這個(gè)划栓,原來的全局變量被隱藏了。如果想使用原來的全局變量条获,需要在變量前面加上“::”, 稱之為作用域解析運(yùn)算符忠荞。這也是C++比C語言優(yōu)越的一點(diǎn)體現(xiàn)。

全局變量 VS 局部變量

??全局變量固然有其優(yōu)勢(shì),所有的函數(shù)都可以訪問委煤,甚至是函數(shù)在調(diào)用的時(shí)候都不用傳遞參數(shù)堂油。但是,過分地使用全局變量也會(huì)使得程序變得不可靠碧绞。計(jì)算經(jīng)驗(yàn)表明府框,程序越能避免對(duì)數(shù)據(jù)進(jìn)行不必要的訪問,就越能保持?jǐn)?shù)據(jù)的完整性讥邻。C++作為一門面向?qū)ο蟮木幊陶Z言迫靖,本身就在數(shù)據(jù)隔離方面邁出了關(guān)鍵性的一步。

加static的全局變量與不加的有何區(qū)別

??如果整個(gè)程序只有一個(gè)源文件兴使,那么在全局變量前加不加static將不會(huì)對(duì)其產(chǎn)生任何影響系宜。但是如果程序由多個(gè)源文件組成,那么static就會(huì)對(duì)該全局變量的作用域產(chǎn)生影響了发魄。加上了static的全局變量蜈首,其作用域?qū)⒈幌薅ㄔ诒疚募?nèi),雖然變量可以在文件內(nèi)部全局調(diào)用欠母,但是其鏈接性將變成內(nèi)部。
??觀察下面一段代碼:

//file1
int error = 20;
...

---------------------

//file2
int error = 5;
void foo() {
    cout << error;
}

??這種情況下吆寨,程序是編不過的赏淌,因?yàn)樗`反了單定義原則(ODR)。file1已經(jīng)創(chuàng)建了error作為外部變量的定義啄清,file2又試圖定義相同的變量六水。但是,如果把程序改成如下形式辣卒,則可以編譯通過:

//file1
int error = 20;
...

-----------------
//file2
static int error = 5;
void foo() {
    cout << error; // user will use error defined in file2
}

const對(duì)于全局變量作用域的影響

??之前講過掷贾,如果不加static修飾的話,默認(rèn)全局變量的鏈接性是外部的荣茫。但是想帅,如果加了const后,該全局變量的鏈接性就會(huì)變成內(nèi)部的了啡莉。

const int fingers = 10;

??以上代碼等價(jià)于:

static const int finger = 10;

??如果我們希望const常量具有外部鏈接性港准,就需要在定義的時(shí)候前面加上extern,如下:

extern const int finger = 10;

??雖然對(duì)于普通的全局變量咧欣,加不加extern不影響浅缸。

函數(shù)的鏈接性(extern 與 static)

??與C語言一樣,C++不允許在一個(gè)函數(shù)中定義另外一個(gè)函數(shù)魄咕,因此所有的函數(shù)存儲(chǔ)持續(xù)性都自動(dòng)為靜態(tài)的衩椒,即整個(gè)程序執(zhí)行期間都一直存在。默認(rèn)情況下,函數(shù)的鏈接性都是外部的毛萌,即全局函數(shù)都可以在文件之間共享苟弛。實(shí)際上,可以在函數(shù)原型前面加上extern朝聋,表明該函數(shù)是在其它文件中定義的嗡午,不過這是可選的。static關(guān)鍵字同樣適用于函數(shù)冀痕,如果一個(gè)函數(shù)被static說明符修飾荔睹,則該函數(shù)只能在該文件中使用,且static必須在函數(shù)的聲明和定義中都使用言蛇。例如:

static int private(double x);
...
static int private(double x) {
...
}

??與此同時(shí)僻他,這還意味著其它文件中可以定義同名的函數(shù)。在此文件中腊尚,靜態(tài)函數(shù)會(huì)覆蓋同名的外部定義的全局函數(shù)吨拗,正如靜態(tài)變量會(huì)覆蓋全局變量一樣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末婿斥,一起剝皮案震驚了整個(gè)濱河市劝篷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌民宿,老刑警劉巖娇妓,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異活鹰,居然都是意外死亡哈恰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門志群,熙熙樓的掌柜王于貴愁眉苦臉地迎上來着绷,“玉大人,你說我怎么就攤上這事锌云≤剑” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵宾抓,是天一觀的道長子漩。 經(jīng)常有香客問我,道長石洗,這世上最難降的妖魔是什么幢泼? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮讲衫,結(jié)果婚禮上缕棵,老公的妹妹穿的比我還像新娘孵班。我一直安慰自己,他們只是感情好招驴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布篙程。 她就那樣靜靜地躺著,像睡著了一般别厘。 火紅的嫁衣襯著肌膚如雪虱饿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天触趴,我揣著相機(jī)與錄音氮发,去河邊找鬼。 笑死冗懦,一個(gè)胖子當(dāng)著我的面吹牛爽冕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播披蕉,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颈畸,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了没讲?” 一聲冷哼從身側(cè)響起眯娱,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爬凑,沒想到半個(gè)月后困乒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贰谣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了迁霎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吱抚。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖考廉,靈堂內(nèi)的尸體忽然破棺而出秘豹,到底是詐尸還是另有隱情,我是刑警寧澤昌粤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布既绕,位于F島的核電站,受9級(jí)特大地震影響涮坐,放射性物質(zhì)發(fā)生泄漏凄贩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一袱讹、第九天 我趴在偏房一處隱蔽的房頂上張望疲扎。 院中可真熱鬧,春花似錦、人聲如沸椒丧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壶熏。三九已至句柠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間棒假,已是汗流浹背溯职。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淆衷,地道東北人缸榄。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像祝拯,于是被迫代替她去往敵國和親甚带。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

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