外部变量

在B语言、C语言和一些其它派生的语言（如C++）中，外部变量即外部的变量。这并不是语言规范中直接明确的概念，因此含义可能有歧义。严格地，“外部”可以指变量名具有的外部链接(external linkage)，据此外部变量指变量名具有外部链接的变量。其它理解导致外延与之具有一定差异，在下面的例子中注释。

注意“变量”的概念在这些语言中本身即具有一些差异。ISO C中没有作为名词的“变量”(variable)这一术语的正式定义，通常即指对象，而ISO C++规定变量通过对象或不是非静态数据成员的引用的声明引入，其中“对象”的概念和ISO C的基本兼容。除非另行说明，下文取其公共含义，即变量均指对象。变量名在此即为标识符（C++的名称外延比标识符更广，在此不考虑非标识符的情形）。

例子 

下面的文件可以作为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 linkage
static int i2 = 2; // definition, internal linkage
extern int i3 = 3; // definition, external linkage
int i4; // tentative definition, external linkage
static 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 disagreement
extern int i1; // refers to previous, whose linkage is external
extern int i2; // refers to previous, whose linkage is internal
extern int i3; // refers to previous, whose linkage is external
extern int i4; // refers to previous, whose linkage is external
extern int i5; // refers to previous, whose linkage is internal

若外延限制为以上理解外延的交集，即文件作用域（C）/全局命名空间作用域（C++）中首次使用extern或没有存储类指示符的声明引入的变量，则没有歧义。绝大多数情况下，“外部变量”都属于这个范畴。

参见 

 C程序设计语言
 声明
 全局变量
 局部变量
 静态变量
 作用域
 函数原型

变量