外部變數
外部變數
外部徠變數是在函數外部定義的全局變數,它的作用域是從變數的定義處開始,到本程序文件的結尾。在此作用域內,全局變數可為各個函數所引用。編譯時將外部變數分配在靜態存儲區。
有時需要在其他文件中使用extern來聲明全局變數,以擴展全局變數的作用域。也可用static聲明全局變數,使該變數不能被其他文件引用。
在B語言、C語言和一些其它派生的語言(如C++)中,外部變數即 外部的徠變數。這並不是語言規範中直接明確的概念,因此含義可能有歧義。嚴格地,“外部”可以指變數名具有的外部鏈接(external linkage),據此外部變數指 變數名具有外部鏈接的變數。其它理解導致外延與之具有一定差異,在下面的例子中註釋。
注意“變數”的概念在這些語言中本身即具有一些差異。ISO C中沒有作為名詞的“變數”(variable)這一術語的正式定義,通常即指對象,而ISO C++規定變數通過對象或不是非靜態數據成員的引用的聲明引入,其中“對象”的概念和ISO C的基本兼容。
extern可省略不寫。
本文件里:在一個文件里,有不止一個函數,外部變數在第一個函數後面定義。若用extern在第一個函數前聲明該變數則該變數可以在第一個函數中使用。
多個文件中:在其他文件中若想要使用該文件中已聲明的全局變數,則在其他文件頭部聲明該變數,即可使用該全局變數。
下面的文件可以作為C或C++(源代碼確保符合ISO C11和ISO C++11)的源文件,分別作為一個翻譯單元,翻譯后鏈接為一個程序。
文件1:
文件2:
在每個翻譯單元中,標識符都必須先被聲明。這個例子里,變數 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:
若外延限制為以上理解外延的交集,即文件作用域(C)/全局命名空間作用域(C++)中首次使用extern或沒有存儲類指示符的聲明引入的變數,則沒有歧義。絕大多數情況下,“外部變數”都屬於這個範疇。
static聲明后該外部變數就只能在本文件中使用。