08-静态持续性、内部链接性
9.2.5 静态持续性、内部链接性
将static限定符用于作用域为整个文件的变量时,该变量的链接性将为内部的。在多文件程序中,内部链接性和外部链接性之间的差别很有意义。链接性为内部的变量只能在其所属的文件中使用;但常规外部变量都具有外部链接性,即可以在其他文件中使用,如前面的示例所示。
如果要在其他文件中使用相同的名称来表示其他变量,该如何办呢?只需省略关键字extern即可吗?
// file1
int errors = 20; // external declaration
...
---------------------------------------------
// file2
int errors = 5; // ??known to file2 only??
void froobish()
{
cout << errors; // fails
...
这种做法将失败,因为它违反了单定义规则。file2中的定义试图创建一个外部变量,因此程序将包含errors的两个定义,这是错误。
但如果文件定义了一个静态外部变量,其名称与另一个文件中声明的常规外部变量相同,则在该文件中,静态变量将隐藏常规外部变量:
// file1
int errors = 20; // external declaration
...
---------------------------------------------
// file2
static int errors = 5; // known to file2 only
void froobish()
{
cout << errors; // uses errors defined in file2
...
这没有违反单定义规则,因为关键字static指出标识符errors的链接性为内部,因此并非要提供外部定义。
注意: 在多文件程序中,可以在一个文件(且只能在一个文件)中定义一个外部变量。使用该变量的其他文件必须使用关键字extern声明它。
可使用外部变量在多文件程序的不同部分之间共享数据;可使用链接性为内部的静态变量在同一个文件中的多个函数之间共享数据(名称空间提供了另外一种共享数据的方法)。另外,如果将作用域为整个文件的变量变为静态的,就不必担心其名称与其他文件中的作用域为整个文件的变量发生冲突。
程序清单9.7和程序清单9.8演示了C++如何处理链接性为外部和内部的变量。程序清单9.7(twofile1.cpp)定义了外部变量tom和dick以及静态外部变量harry。这个文件中的main()函数显示这3个变量的地址,然后调用remote_access()函数,该函数是在另一个文件中定义的。程序清单9.8(twofile2.cpp)列出了该文件。除定义remote_access()外,该文件还使用extern关键字来与第一个文件共享tom。接下来,该文件定义一个名为dick的静态变量。static限定符使该变量被限制在这个文件内,并覆盖相应的全局定义。然后,该文件定义了一个名为harry的外部变量,这不会与第一个文件中的harry发生冲突,因为后者的链接性为内部的。随后,remote-access()函数显示这3个变量的地址,以便于将它们与第一个文件中相应变量的地址进行比较。别忘了编译这两个文件,并将它们链接起来,以得到完整的程序。
程序清单9.7 twofile1.cpp
// twofile1.cpp -- variables with external and internal linkage
#include <iostream> // to be compiled with two file2.cpp
int tom = 3; // external variable definition
int dick = 30; // external variable definition
static int harry = 300; // static, internal linkage
// function prototype
void remote_access();
int main()
{
using namespace std;
cout << "main() reports the following addresses:\n";
cout << &tom << " = &tom, " << &dick << " = &dick, ";
cout << &harry << " = &harry\n";
remote_access();
return 0;
}
程序清单9.8 twofile2.cpp
// twofile2.cpp -- variables with internal and external linkage
#include <iostream>
extern int tom; // tom defined elsewhere
static int dick = 10; // overrides external dick
int harry = 200; // external variable definition,
// no conflict with twofile1 harry
void remote_access()
{
using namespace std;
cout << "remote_access() reports the following addresses:\n";
cout << &tom << " = &tom, " << &dick << " = &dick, ";
cout << &harry << " = &harry\n";
}
下面是编译程序清单9.7和程序清单9.8生成的程序的输出:
main() reports the following addresses:
0x0041a020 = &tom, 0x0041a024 = &dick, 0x0041a028 = &harry
remote_access() reports the following addresses:
0x0041a020 = &tom, 0x0041a450 = &dick, 0x0041a454 = &harry
从上述地址可知,这两个文件使用了同一个tom变量,但使用了不同的dick和harry变量。具体的地址和格式可能随系统而异,但两个tom变量的地址将相同,而两个dick和harry变量的地址不同。