extern宣告變數無外乎如下兩種:
1、宣告全域性變數
2、宣告函式
今天我們只談extern,什麼const、static之類等等與之相關或不相關的一律忽略,下面就分別對以上兩種情況一一講解
宣告和定義
既然提到extern宣告變數,那我們就必須搞清楚宣告和定義的區別。
這裡我們將普通資料變數和函式統稱變數。從記憶體分配角度來說,宣告和定義的區別在於宣告乙個變數不會分配記憶體,而定義乙個變數會分配記憶體。乙個變數可以被宣告多次,但是只能被定義一次。
基於以上前提,我們可以把宣告和定義模擬為指標和記憶體的關係。我們知道,指標其實就是指向記憶體的乙個符號,變數的定義就好比一塊記憶體區域,而宣告就好比它的指標,可以有多個指標指向同乙個記憶體區域,而乙個指標只能指向乙個記憶體區域,這樣就很好理解為什麼變數只能被定義一次,如果被定義多次,那就會分配多個記憶體,這樣你通過變數的宣告到底去找哪塊記憶體區域呢,這會是個問題。
對於資料來說,宣告和定義往往是同時存在的,比如下面的一行語句
複製**
**如下:
int data;
這樣既宣告了data同時也定義了data,怎樣做到只宣告而不定義呢,用extern就可以了
複製**
**如下:
extern int data;
對於函式來說,宣告和定義就很容易區分了,一般我們會將宣告放在標頭檔案而將定義放在原始檔裡
複製**
**如下:
void hello();
這是乙個函式的宣告,而
複製**
**如下:
void hello()
這是乙個函式的定義。當然,函式的宣告和定義也可以同時發生,如果我們沒有標頭檔案而只有原始檔,並且在原始檔裡並沒有void hello();這樣的語句,那麼這個函式的宣告和定義就同時發生了,此時如果我們在原檔案裡想要呼叫函式hello(),你呼叫的**必須在函式定義之後。
其實上面的要點只在於一句話:使用變數之前必須宣告,宣告可以有多次,而定義只能有一次。記住這句話,後面的就都很容易理解了。
extern宣告全域性變數
我們先來看如下例子,現有三個檔案:test.h, test.cpp, main.cpp,其中main.cpp和test.cpp需要共享乙個變數g_name,三個檔案的內容如下
複製**
**如下:
/* test.h */
#ifndef _test_h_
#define _test_h_
#include
std::string g_name;
void hello();
#endif
/* test.cpp */
#include
#include "test.h"
void hello()
/* main.cpp */
#include "test.h"
std::string g_name;
int main()
三者關係為,test.cpp包含了test.h,main.cpp也包含了test.h,這裡的包含其實就是include。我們執行編譯命令
複製**
**如下:
g++ main.cpp test.cpp
編譯報錯redefinition of 'g_name',說的是g_name被重定義了
我們看一下g_name出現的地方,乙個是在test.h裡,乙個是在main.cpp裡,兩條語句都是std::string g_name,前面我們已經說過,這樣的方式既宣告也定義了變數,那g_name是如何被重定義的呢,首先我們需要理解include的含義,我們可以將include乙個標頭檔案理解為在該行展開標頭檔案裡的所有**,由於main.cpp包含了test.h,我們在那一行將test.h的內容展開,就會發現main.cpp裡有兩句std::string g_name;所以在main.cpp裡,g_name被定義了兩次。
由於我們可以將include標頭檔案理解為展開**,所以編譯的時候其實不需要指定標頭檔案,只需要原始檔就夠了。需要注意的是,重定義並不是指在同乙個原檔案裡定義多次,而是指在整個**空間裡,比如上面的例子是就是指在test.cpp和main.cpp裡,其實上面的例子裡g_name是被重定義了三次,其中test.cpp裡一次,main.cpp裡兩次。
那上面重定義的問題怎麼解決呢,很簡答,將test.h裡的std::string g_name;改為extern std::string g_name;就可以了,由於extern語句只宣告變數而不定義變數,因此test.cpp和main.cpp展開標頭檔案後,也只是將g_name宣告了兩次,而真正的定義還是在main.cpp裡
extern宣告函式
還是上面的例子,我們怎麼在main.cpp裡不包含標頭檔案就可以呼叫hello函式呢,既然今天的主題是extern,不用提醒也知道,使用extern就可以了,**如下
複製**
**如下:
/* test.cpp */
#include
#include
// 宣告g_name
extern std::string g_name;
// 宣告和定義void hello()
void hello()
/* main.cpp */
#include
// 宣告和定義g_name
std::string g_name;
// 宣告void hello()
extern void hello();
int main()
注意這裡用到extern宣告變數和函式兩種場景,我分別在語句後面做了注釋。編譯命令如下
複製**
**如下:
g++ main.cpp test.cpp
這裡我們並沒有用到頭檔案,但是依然可以在不同檔案間共享變數和函式,這一切都是extern的功勞!
總結要了解extern主要搞清以下幾個概念:
1、宣告和定義的區別。全域性**空間裡,變數可以有多個宣告,但只能有乙個定義
2、include標頭檔案等同於展開標頭檔案裡的**
了解了以上兩點,再來分析extern的用法,是不是就會清晰很多了
c 變數宣告extern說明
當使用extern關鍵字修飾變數 未初始化 表示變數宣告。當在另乙個檔案中,為extern關鍵字修飾的變數賦值時,表示變數定義。宣告在標頭檔案裡面,定義的檔案裡面包含有該宣告的標頭檔案。header.件如下 ifndef header h define header h 定義global x變數 在...
c 中extern用來宣告全域性變數
宣告 在某個標頭檔案1.h 可以在同一檔案中或同一程式的不同檔案中出現多次 定義 在任何乙個原始檔x.cpp 只能定義一次!include 1.h 使用 要使用這個全域性變數,只要包含1.h就行了。在全域性域中定義的物件 如果沒有指定顯式的初始值 則該儲存區被初始化為 0 因此下面兩個定義中 var...
C 變數宣告(extern用法總結)
變數宣告向編譯器保證變數以給定的型別和名稱存在,這樣編譯器在不需要知道變數完整細節的情況下也能繼續進一步的編譯。變數宣告只在編譯時有它的意義,在程式連線時編譯器需要實際的變數宣告。當使用多個檔案且只在其中乙個檔案中定義變數時 定義變數的檔案在程式連線時是可用的 變數宣告就顯得非常有用。您可以使用ex...