外部變數

外部變數是在函式外部定義的全局變數,它的作用域是從變數的定義處開始,到本程式檔案的結尾。在此作用域內,全局變數可為各個函式所引用。編譯時將外部變數分配在靜態存儲區。

基本介紹

  • 中文名:外部變數
  • 實質:函式外部定義的全局變數
  • 作用域:從變數的定義處開始
  • 類型:函式
定義,用extern聲明,例子,用static聲明外部變數,

定義

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

用extern聲明

extern可省略不寫。
本檔案里:在一個檔案里,有不止一個函式,外部變數在第一個函式後面定義。若用extern在第一個函式前聲明該變數則該變數可以在第一個函式中使用。
多個檔案中:在其他檔案中若想要使用該檔案中已聲明的全局變數,則在其他檔案頭部聲明該變數,即可使用該全局變數。
file1.c file2.cint 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 linkageint i4; // tentative definition, external linkagestatic int i5; // tentative definition, internal linkageint i1; // valid tentative definition, refers to previousint i2; // 6.2.2 renders undefined, linkage disagreementint i3; // valid tentative definition, refers to previousint i4; // valid tentative definition, refers to previousint 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聲明後該外部變數就只能在本檔案中使用。

相關詞條

熱門詞條

聯絡我們