C++: extern關鍵字功能和用法研究
今天遇到在aaa.cpp檔案中定義如下函式:
在bbb.h檔案中有以下宣告:
但在aaa.cpp中沒有包含相關標頭檔案,那麼為什麼可以呼叫相關函式,這就是extern的功能。
1. extern的功能一般是宣告可用於多檔案之間的函式和變數,應用在多檔案間需要共享某些程式碼時。
2. 變數的宣告和定義:
C++語言支援分離式編譯機制,該機制允許將程式分割為若干個檔案,每個檔案可被獨立編譯。為了將程式分為許多檔案,則需要在檔案中共享程式碼,例如一個檔案的程式碼可能需要另一個檔案中中定義的變數。
為了支援分離式編譯,C++允許將宣告和定義分離開來。變數的宣告規定了變數的型別和名字,即使一個名字為程式所知,一個檔案如果想使用別處定義的名字則必須包含對那個名字的宣告。定義則負責建立與名字關聯的實體,定義還申請儲存空間。
如果想宣告一個變數而非定義它,就在變數名前新增extern關鍵字,而且不要顯式地初始化變數:
extern int i; //宣告i而非定義 int j; //宣告並定義i
但我們也可以給由extern關鍵字標記的變數賦一個初始值,但這樣就不是一個聲明瞭,而是一個定義:
extern int v = 2;
int v = 2; //這兩個語句效果完全一樣,都是v的定義
注意: 變數能且只能被定義一次,但是可以被宣告多次。
3. 在多個檔案中共享const物件:
預設情況下,一個const物件僅在本檔案內有效,如果多個檔案中出現了同名的const變數時,其實等同於在不同的檔案中分別定義了獨立的變數。
某些時候有這樣一種const變數,它的初始值不是一個常量表達式,但又確實有必要在檔案間共享。這種情況下,我們不希望編譯器為每個檔案分別生成獨立的變數。我們想讓這類const物件像其他非常量物件一樣工作,也就是說,只在一個檔案中定義const,而在其他多個檔案中宣告並使用它。
方法是對於const變數不管是宣告還是定義都新增extern關鍵字,這樣只需要定義一次就可以了:
//file1.cpp定義並初始化和一個常量,該常量能被其他檔案訪問
extern const int bufferSize = function();
//file1.h標頭檔案
extern const int bufferSize; //與file1.cpp中定義的是同一個
file1.h標頭檔案中的宣告也由extern做了限定,其作用是指明bufferSize並非本檔案獨有,它的定義將出現在別處。
4. 模板的控制例項化
當兩個或者多個獨立編譯的原始檔中使用了相同的模板並且提供了相同的模板引數時,每個檔案中都會有該模板的一個例項。
在大系統中,在多個檔案中例項化相同的模板的額外開銷可能非常嚴重,在C++11新標準中,我們可以通過顯式例項化來避免這種開銷。一個顯式例項化具有如下形式:
extern template declaration; //例項化宣告
template declaration; //例項化定義
declaration是一個類或函式的宣告,其中所有的模板引數都已經被替換成為模板實參。例如:
extern template class vec<string>; //宣告
template int sum(const int, const int); //定義
當編譯器遇到extern模板宣告時,它不會在本檔案中生成例項化程式碼,將一個例項化宣告為extern就表示承諾在程式的其他位置有該例項化的一個非extern定義。對於一個給定的例項化版本,可能有多個extern宣告,但必須只有一個定義。
由於編譯器在使用一個模板時自動對其例項化,因此extern宣告必須出現在任何使用此例項化吧版本的程式碼之前。
由於以上討論可知:extern一般是使用在多檔案之間需要共享某些程式碼時。
參考文章: