10.1.2 控制连接

一般情况下,在文件作用域(file scope)内的所有名字(即不嵌套在类或函数中的名字)对程序中的所有翻译单元来说都是可见的。这就是所谓的外部连接(external linkage),因为在连接时这个名字对连接器来说是可见的,对单独的翻译单元来说,它是外部的。全局变量和普通函数都有外部连接。

有时可能想限制一个名字的可见性。想让一个变量在文件范围内是可见的,这样这个文件中的所有函数都可以使用它,但不想让这个文件之外的函数看到或访问该变量,或不想这个变量的名字与外部的标识符相冲突。

在文件作用域内,一个被明确声明为static的对象或函数的名字对翻译单元(用本书的术语来说也就是出现声明的.cpp文件)来说是局部于该单元的。这些名字有内部连接(internal linkage)。这意味着可以在其他的翻译单元中使用同样的名字,而不会发生名字冲突。

内部连接的一个好处是这个名字可以放在一个头文件中而不用担心连接时发生冲突。那些通常放在头文件里的名字,如常量、内联函数,在默认情况下都是内部连接的(当然常量只有在C++中默认情况下是内部连接的,在C中它默认为外部连接)。注意连接只引用那些在连接/装载期间有地址的成员,因此类声明和局部变量并不连接。

10.1.2.1 冲突问题

下面例子说明了static的两个含义是怎样彼此交叉的。所有的全局对象都是隐含为静态存储的,所以如果定义(在文件作用域)

10.1.2 控制连接 - 图1

则a被存储在程序的静态数据区,在进入main()函数之前,a即已初始化了。另外,a对所有的翻译单元都是全局可见的。用可见性术语来讲,static(只在翻译单元内可见)的反义是extern,它明确地声明了这个名字对所有的翻译单元都是可见的。所以上面的定义和下面的定义是相同的。

10.1.2 控制连接 - 图2

但如果这样定义:

10.1.2 控制连接 - 图3

只不过改变了a的可见性,现在a成了一个内部连接,但存储类型没有改变—对象总是驻留在静态数据区,而不管是static还是extern。

一旦进入局部变量,static就不会再改变变量的可见性(这时extern是没有意义的),而只是改变变量的存储类型。

如果把局部变量声明为extern,这意味着某处已经存在一个存储区(所以该变量对函数来说实际上是全局的),请看下面的例子。

10.1.2 控制连接 - 图4

对函数名(非成员函数),static和extern只会改变它们的可见性,所以如果说:

10.1.2 控制连接 - 图5

它和没有修饰时的声明是一样的:

10.1.2 控制连接 - 图6

如果定义:

10.1.2 控制连接 - 图7

它意味着f()只在本翻译单元内是可见的,这有时称作文件静态(file static)。