複製鏈接
請複製以下鏈接發送給好友

外部變量

鎖定
外部變量是在函數外部定義的全局變量,它的作用域是從變量的定義處開始,到本程序文件的結尾。在此作用域內,全局變量可為各個函數所引用。編譯時將外部變量分配在靜態存儲區。
中文名
外部變量
適用領域
數學、計算機
所屬學科
計算機科學
實    質
函數外部定義的全局變量
作用域
從變量的定義處開始
類    型
函數

外部變量定義

有時需要在其他文件中使用extern來聲明全局變量,以擴展全局變量的作用域。 也可用static聲明全局變量,使該變量不能被其他文件引用。
B語言C語言和一些其它派生的語言(如C++)中,外部變量外部變量。這並不是語言規範中直接明確的概念,因此含義可能有歧義。嚴格地,“外部”可以指變量名具有的外部鏈接(external linkage),據此外部變量指變量名具有外部鏈接的變量。其它理解導致外延與之具有一定差異,在下面的例子中註釋。
注意“變量”的概念在這些語言中本身即具有一些差異。ISO C中沒有作為名詞的“變量”(variable)這一術語的正式定義,通常即指對象,而ISO C++規定變量通過對象或不是非靜態數據成員的引用的聲明引入,其中“對象”的概念和ISO C的基本兼容。 [1] 

外部變量extern聲明

extern可省略不寫。
本文件裏:在一個文件裏,有不止一個函數,外部變量在第一個函數後面定義。若用extern在第一個函數前聲明該變量則該變量可以在第一個函數中使用。
多個文件中:在其他文件中若想要使用該文件中已聲明的全局變量,則在其他文件頭部聲明該變量,即可使用該全局變量。 [1] 
file1.c file2.c
int i,j; //定義全局變量 extern int i,j; //外部變量説明, extern可以省略
char c; extern char c;
void func() void func1()
{ {
i = 100; printf(" i = %d, j = %d ", i, j);
j = 10;
} }

外部變量例子

下面的文件可以作為C或C++(源代碼確保符合ISO C11和ISO C++11)的源文件,分別作為一個翻譯單元,翻譯後鏈接為一個程序。
文件1:
 int GlobalVariable;  // 同一個翻譯單元中,在文件作用域(C)或全局命名空間作用域(C++)的首次聲明的變量名隱式具有外部鏈接  void SomeFunction(void); // 不是函數定義的函數聲明,因為明確指定了具體類型,在C語言中是函數原型  int main() {    GlobalVariable = 1;    SomeFunction();  }
文件2:
 extern int GlobalVariable;  // 通過關鍵字extern顯式指定被聲明的變量名具有外部鏈接  // static int GlobalVariable;  // 若使用static關鍵字,可顯式指定被聲明的變量名具有內部鏈接,這樣就不會指稱翻譯單元中聲明的具有外部鏈接的對象,即使變量名相同  void SomeFunction(void) { // 函數定義    // int GlobalVariable; // 若在這裏聲明變量,則隱藏塊作用域外部的變量名,這個變量沒有鏈接,和塊作用域外部的變量名不同    // extern int GlobalVariable; // 若在這裏以extern聲明同名變量,則重複聲明之前的變量,鏈接取決於之前的聲明,可能是或者不是外部鏈接    ++GlobalVariable;  }
在每個翻譯單元中,標識符都必須先被聲明。這個例子裏,變量 GlobalVariable 在文件1中被聲明,這個聲明同時是定義。為了在文件2中使同一個標識符指稱相同實體,它必須被聲明具有外部鏈接。
ISO C要求函數或對象的標識符若被使用則有且僅有一個外部定義,或未被使用時可以沒有定義或具有一個定義,否則行為未定義。通常除非使用擴展(例如弱符號),實現(鏈接器)一般會有檢查。
ISO C++規定合式(well-formed)必須在符合語法規則、可診斷語義規則的同時遵守One Definition Rule,其中多個翻譯單元內的同一個實體必須具有唯一定義,這包括具有外部鏈接的變量。不管有多少個翻譯單元,定義在整個程序中有且僅有一個。對於跨翻譯單元的情形,如果違反此規定,通常會產生鏈接錯誤。
除了外部鏈接,“外部”可能被理解為“在塊作用域外部”,見例子中SomeFunction函數定義中的註釋。這裏,“外部”變量不一定具有外部鏈接(比如,首次聲明時顯式使用了static關鍵字指定變量名具有內部鏈接,或者(C++)聲明在具有內部鏈接的無名命名空間(unnamed namespace)內部)。由於這些微妙的歧義,通常不使用這種理解。
由於C語言中外部鏈接的對象被習慣性誤稱為全局變量,“外部”還可能會被誤解為“全局”——嚴格地,這種理解的“外部”着眼於特定的源文件,指非當前翻譯單元。但是事實上C語言本身並沒有嚴格約定“全局”的含義。和C語言不同的是,C++存在嚴格意義上的全局變量,此處“全局”被正式定義為全局命名空間作用域。但是,這個概念的外延實際上和C++的“外部變量”不同:非全局命名作用域的變量的名稱可以具有外部鏈接,這不是全局變量;而全局命名空間作用域中也可以直接使用static聲明具有內部鏈接的全局變量。
此外,ISO C規定沒有初值符且沒有存儲類指示符(storage specifier)或static指定的對象聲明是tentative definition(ISO C++則明確禁止),和重複聲明一起可能顯著加劇上述理解的混亂。以下例子引用自ISO C11 6.9.2:
int i1 = 1; // definition, external linkagestatic 
int i2 = 2; // definition, internal linkageextern 
int i3 = 3; // definition, external linkage
int i4; // tentative definition, external linkagestatic 
int i5; // tentative definition, internal linkage
int i1; // valid tentative definition, refers to previous
int i2; // 6.2.2 renders undefined, linkage disagreement
int i3; // valid tentative definition, refers to previous
int i4; // valid tentative definition, refers to previous
int i5; // 6.2.2 renders undefined, linkage disagreementextern 
int i1; // refers to previous, whose linkage is externalextern 
int i2; // refers to previous, whose linkage is internalextern 
int i3; // refers to previous, whose linkage is externalextern 
int i4; // refers to previous, whose linkage is externalextern 
int i5; // refers to previous, whose linkage is internal
若外延限制為以上理解外延的交集,即文件作用域(C)/全局命名空間作用域(C++)中首次使用extern或沒有存儲類指示符的聲明引入的變量,則沒有歧義。絕大多數情況下,“外部變量”都屬於這個範疇。

外部變量static聲明

static聲明後該外部變量就只能在本文件中使用。
[2] 
參考資料
  • 1.    "The C Standard (C99 with Technical corrigenda TC1, TC2, and TC3 included)" . (3.61 MiB).
  • 2.    李志聰. MFC中定義全局變量和全局函數的方法[J]. 電腦知識與技術, 2007, 1(3):184-185.