[C++]static详细说明
static用于声明全局变量(包括类的对象),局部变量,全局函数,类的成员变量和成员函数。即,static不能用于类、结构、枚举、联合的声明。
static有如下用途:
①使变量具有初值:
静态变量具有初值。局部变量是没有初值,而static的局部变量将有初值。全局变量本身就具有初始值,所以static不发生作用。static用于全局变量,更多是用于解决命名冲突问题。
#include <iostream> void PrintNormal() { int i; double d; char c; int* p; std::cout << a << std::endl; std::cout << i << std::endl; // output: -858993460 std::cout << d << std::endl; // output: -9.25596e+061 std::cout << c << std::endl; // output: (乱码) std::cout << p << std::endl; // output: CCCCCCCC } void PrintStatic() { static int i; static double d; static char c; static int* p; std::cout << a << std::endl; std::cout << i << std::endl; // output: 0 std::cout << d << std::endl; // output: 0 std::cout << c << std::endl; // output: (空) std::cout << p << std::endl; // output: 00000000 } int main() { PrintNormal(); PrintStatic(); system("pause"); }
②声明全局变量:
如果一个变量在所有的块之外,那么这个变量是全局变量,具有static duration(即也有初始值)和external linkage特性。注意要使用extern关键字。如果两个编译单元都使用同名的全局变量,将报错。(Visual Studio中。Linux下参考强符号、弱符号)
// external linkage int a;
#include <iostream> extern int a; int main() { std::cout << a << std::endl; system("pause"); }
但是,用static修饰后,此变量将变为external linkage。无法被外部Link。
// external linkage static int a = 5;
#include <iostream> static int a; // 将报错error LNK2001: 无法解析的外部符号 "int a" (?a@@3HA) //extern int a; int main() { std::cout << a << std::endl; system("pause"); }
然而,static不支持类、结构、枚举的修饰,比起static修饰,更推荐使用namespace解决命名冲突(参见匿名namespace)。
③声明全局函数
全局函数类似,如果要改变其external linkage的特性,需要使用static。
④声明局部变量
用static声明局部变量虽然不改变其可见性,但变量仍然是static duration的,在其可见域外,仍可以使用地址访问之。
#include <iostream> int* p; void foo() { static int a; if (a == 0) { a = 10; p = &a; } a++; } void main() { foo(); // 将报错,a不可见 //std::cout << a << std::endl; std::cout << *p << std::endl; // 11 *p = 20; foo(); std::cout << *p << std::endl; // 21 system("pause"); }
⑤声明类的成员变量
除了显然意见的作用外,有两个注意点:
1. static的成员变量必须在file scope定义(即便不改变初值也要声明)
#include <iostream> class A { public: static int a; }; // 如果不定义,会报错 /* error LNK2001: 无法解析的外部符号 "public: static int A::a" (?a@A@@2HA) */ // 如果在定义时增加了static关键字,会报错 /* error C2720: “A::a”: 成员上的“static ”存储类说明符非法 */ //static int A::a; // 定义的时候可以指定初值 int A::a = 5; void main() { std::cout << A::a << std::endl; system("pause"); }
2. 对于const static类型,除了以上方法外,还可以直接在类中初始化~不是const不成哦~
#include <iostream> class A { public: static const int a = 5; }; // 如果类中初始化了,这里就不能再次初始化了 //const int A::a = 5; void main() { std::cout << A::a << std::endl; system("pause"); }
⑥声明类的成员函数
显而易见的作用
附录:
union的成员是特殊的。不能将其成员定义为static。原因?看看union是干什么的吧~
这些英文术语极其难翻译,干脆直接贴上来。后边有解释。
static duration:静态生存期,程序创建时即分配此变量的内存,存放在全局静态存储区。程序创建时分配,结束时销毁。具有初始值。
C++内存分配:静态存储区、常量存储区、栈、堆、自由存储区。
全局静态存储区:程序创建时分配,结束时销毁。
常量存储区:不允许修改。程序创建时分配,结束时销毁。
栈:局部变量、函数参数等。生存期结束后销毁。空间较小,不过可以手动修改。
堆:动态内存分配(new)。编译器不负责回收。
自由存储区:动态内存分配(malloc)。编译器不负责回收。
external linkage:可以外部链接的。即其他编译单元(.cpp文件)可以使用此变量。也就是说,如果在两个编译单元中使用了同名的static变量,会出错~
internal linkage:不能外部链接。