C/C++ 中的 static

来源:互联网 发布:小学语文教学软件 编辑:程序博客网 时间:2024/05/20 09:11

一 、函数内部的静态变量

在函数体内定义一个局部变量时,编译器在每次函数调用时,使堆栈的指针向下移动,为这些局部变量分配内存。

定义一个全局变量将不仅仅只受这个函数控制。

在C/C++函数内部定义的 static 对象,将存储在程序的静态数据区(static data area)中。

char * c = "abc" 这样的赋值会得到一个警告:不建议从字符常量到 char * 的转换,最好在前面加上 const

  1 #include <iostream>  2 using namespace std;  3  4 char oneChar(const char * charArray = 0){  5         static const char * s;  6         if(charArray){  7                 s = charArray;  8                 return *s;  9         }else{ 10                 cout <<"un initialized\n"; 11         } 12         if( * s == '\0'){ 13                 return 0; 14         } 15         return *s++; 16 } 17 18 char * a = "abcdefghijklmnopqrstuvwxyz"; 19 20 int main(){ 21         oneChar(a); 22         char c; 23         while((c = oneChar()) != 0) 24                 cout << c <<endl; 25         return 0; 26 }

从上例可以看到 static const char * s 在每次函数调用时都保留了值。

可以看出来,在上面的函数中容易产生多线程的问题;在设计包含静态变量的函数时,应该记住多线程的问题。


二、静态对象的析构函数

静态对象的析构函数,在程序从main() 中退出时,或者标准C库的 exit()被调用时才被调用。(注意:使用abor() 来退出程序,静态对象的析构函数并不会调用)

如果一个包含局部静态对象的函数从未被调用,那么这个对象的构造函数也不会被调用。

同普通对象的销毁一样,静态对象的销毁也是按照与初始化相反的顺序进行的。

  2 #include <fstream>  3 using namespace std;  4  5 ofstream out("statdest.out");  6  7 class Obj{  8         char c;  9 public: 10         Obj(char cc):c(cc){ 11                 out<<"Obj::Obj() for "<<c<<endl; 12         } 13         ~Obj(){ 14                 out<<"Obj::~Obj() for "<<c<<endl; 15         } 16 }; 17 18 Obj a('a'); 19 20 void f(){ 21         static Obj b('b'); 22 } 23 24 void g(){ 25         static Obj c('c'); 26 } 27 28 int main(){ 29         out <<"inside main()"<<endl; 30         f(); 31         out <<"leaving main()"<<endl; 32 33         return 0; 34 }

注意跟踪文件ofstream 的对象out 也是一个静态对象。

在C++ 中,全局静态对象的构造函数是在main()之前调用的,这样就有了一个在进入main() 之前执行一段代码的方法。

三、变量可见性

所有的全局对象都是隐含为静态存储的。

       int a = 100;

        则 a 被存储在程序的静态数据区,在进入main() 之前,a 已经初始化了。另外,a 对所有的编译单元都是全局可见的。用可见性术语来说,static(只在翻译单元内可见),extern 则明确声明对所有翻译单元都可见。

所以上面的定义和 extern int a = 0 是一样的

但如果这样定义:

static int a = 0  只是改变了a 的可见性,只在本翻译单元内,有时叫文件静态(file static),但并没有改变存储类型—— 仍然驻留在静态数据区,而不管是static 还是 extern

在局部变量中,就总是内部链接了,extern 的修饰没有意义;使用 static 时只会改变变量的存储类型。


四、定义静态数据成员的存储

        因为类的静态数据成员有着单一的存储空间,所有必须在一个单独的地方定义,编译器不会分配存储空间,如果一个静态数据成员被声明但没有定义,则连接器会报告错误。

定义必须出现在类的外部(不允许内联),而且只能定义一次。

(1)这些变量唯一合法的初始化地方就是在定义时

(2)这些变量只能够被定义一次

以上两点来保证变量只被创建者所控制。

 

静态成员函数:

为类的全体对象服务。 可以用普通的方法调用静态成员函数,用“ .” 或者“->” 把它和一个对象相联系。一个更典型的方法是自我调用。

静态成员函数不能访问一般的数据成员,而只能访问静态的数据成员。原因在于:对象的地址(this)是被隐式传递到调用函数的;但static 函数没有this,因此无法访问一般成员。静态函数在速度上比全局函数有少许增长,不仅没有传递this所需要的额外开销,而且还有使得函数在类内的好处。

 

Static initialization dependency:

对于作用域为多个翻译单元的静态对象来说,不能保证初始化顺序,这可能会导致一些问题。

0 0