在看這篇文章之前,先問自己一個問題:加上static關鍵字後的名字可能擁有外部連結期嗎?如果你已經很確定地知道答案,並且和這篇文章的最後結論相同,那麼恭喜你,不用看這篇文章了,因為我將要講的你都知道了。
影響對象的儲存期
儲存期,又稱storage duration,是指變數所佔用記憶體空間的生命期。也就是說,它決定了在整個程式的執行過程中該空間必須存在的時間段。它大於等於對象的生命期。C++03定義的儲存期包括static(靜態儲存期)、dynamic(動態儲存裝置期)和automatic(自動儲存期)。
static關鍵字對Object Storage Service期的影響主要反映在局部變數上。
void f(){ // Automatic storage duration int i = 10; // Static storage duration static int j = 10;}
變數 i 具有自動儲存期,也就是說存放 i 的空間從左括弧{開始, 到右括弧} 結束。(注意,大多數編譯器都會在一個局部範圍(block)開始的時候通過加減棧指標寄存器(SP/ESP/RSP)來為用到的局部變數分配所需的棧空間。所以,實際空間從 { 就開始存在了,而非定義處。)相比之下,加了static的變數j具有靜態儲存期,它的空間從程式載入直到程式結束始終存在。
影響對象的連結期
連結期,又稱linkage,控制著對象的可見度。它和範圍(scope)的區別是:範圍決定了在同一個編譯單元(包含標頭檔以後的源檔案)中該對象的可見度。而連結期決定了跨多個編譯單元時對象的可見度。C++03定義的連結期包括external(外部連結期)、internal(內部連結期)、no(無連結期)。
static關鍵字對對象連結期的影響主要反映在全域變數、函數上。
// A.cpp// External linkage by defaultint i = 10;// Internal linkagestatic int j = 10;// B.cppextern int i;extern int j;int main(){ int x = i; // Link eror below! Unresolved external symbol "j". // int y = j;}
全域變數預設具有外部連結期,就是全域可見——在其他編譯單元(這裡是B.cpp)中可見。加上static之後就變成了內部連結期,所以在其他檔案中無妨訪問,連結器報錯。
函數就不舉例了,一樣的。加了static的函數只有本編譯單元可以調用。
如果說到目前為止你都很清楚我說的,那麼下面這個你可能覺得比較驚訝,static還可以使名字具有外部連結期!
// namespace scope class// MyClass.hclass MyClass{public: // No linkage int m_i; // External linkage! static int m_j;};// MyClass.cpp#include "MyClass.h"int MyClass::m_j = 10;// Another.cpp#include "MyClass.h"int main(){ MyClass::m_j = 20; // Compile error below! // m_i = 1; // MyClass::m_i = 1;}
這裡,普通的成員變數是沒有任何連結期的,因為在它的範圍(class scope)以外無法通過名字m_i去直接存取它。但靜態成員變數擁有外部連結期,所以可以直接在其他編譯單元中訪問,當然前提是加上類名限定(::)。
最後,順便提一下,成員函數無論加不加static,都具有外部連結期。