外部变量是在
函数外部定义的
全局变量,它的
作用域是从
变量的定义处开始,到本
程序文件的结尾。在此作用域内,全局变量可为各个函数所引用。编译时将外部变量分配在静态存储区。
定义
有时需要在其他文件中使用
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声明
static声明后该外部变量就只能在本文件中使用。