在看这篇文章之前,先问自己一个问题:加上static关键字后的名字可能拥有外部链接期吗?如果你已经很确定地知道答案,并且和这篇文章的最后结论相同,那么恭喜你,不用看这篇文章了,因为我将要讲的你都知道了。
影响对象的存储期
存储期,又称storage duration,是指变量所占用内存空间的生命期。也就是说,它决定了在整个程序的执行过程中该空间必须存在的时间段。它大于等于对象的生命期。C++03定义的存储期包括static(静态存储期)、dynamic(动态存储期)和automatic(自动存储期)。
static关键字对对象存储期的影响主要反映在局部变量上
void f() { // Automatic storage duration int i = 10; // Static storage duration static int j = 10; }
变量 i 具有自动存储期,也就是说存放 i 的空间从左括号{开始, 到右括号} 结束。(注意,大多数编译器都会在一个局部作用域(block)开始的时候通过加减栈指针寄存器(SP/ESP/RSP)来为用到的局部变量分配所需的栈空间。所以,实际空间从 { 就开始存在了,而非定义处。)相比之下,加了static的变量j具有静态存储期,它的空间从程序载入直到程序结束始终存在。
影响对象的链接期
链接期,又称linkage,控制着对象的可见性。它和作用域(scope)的区别是:作用域决定了在同一个编译单元(包含头文件以后的源文件)中该对象的可见性。而链接期决定了跨多个编译单元时对象的可见性。C++03定义的链接期包括external(外部链接期)、internal(内部链接期)、no(无链接期)。
static关键字对对象链接期的影响主要反映在全局变量、函数上。
// A.cpp // External linkage by default int i = 10; // Internal linkage static int j = 10; // B.cpp extern int i; extern int j; int main() { int x = i; // Link eror below! Unresolved external symbol "j". // int y = j; }
全局变量默认具有外部链接期,就是全局可见——在其他编译单元(这里是B.cpp)中可见。加上static之后就变成了内部链接期,所以在其他文件中无妨访问,链接器报错。
函数就不举例了,一样的。加了static的函数只有本编译单元可以调用。
如果说到目前为止你都很清楚我说的,那么下面这个你可能觉得比较惊讶,static还可以使名字具有外部链接期!
// namespace scope class // MyClass.h class MyClass { public: // No linkage int m_i; // External linkage! static int m_j; }; // MyClass.cpp #include "MyClass.h" int MyClass::m_j = 10; // Another.cpp #include "MyClass.h" int main() { MyClass::m_j = 20; // Compile error below! // m_i = 1; // MyClass::m_i = 1; }
这里,普通的成员变量是没有任何链接期的,因为在它的作用域(class scope)以外无法通过名字m_i去直接访问它。但静态成员变量拥有外部链接期,所以可以直接在其他编译单元中访问,当然前提是加上类名限定(::)。
最后,顺便提一下,成员函数无论加不加static,都具有外部链接期。