在C中,static被称为storage class
可以说,在C中,static的作用相当直观且简单。
当其用来修饰全局变量时,该变量的作用域为该编译单元;修饰局部变量时,表明将该变量存储在特定区域,函数调用返回后,该变量不可访问,但存储空间及其存储数据被保存下来,再次调用该函数时可以访问该存储,且数据是上次调用时存储其中的。也就是说,该函数得到了一个永久的、私有的存储。
对于函数来说,使用static意味着该函数只在该编译单元内可见,不使用则表明该函数是global的,所有的地方都可用——因为函数默认的linkage是external的。用static修饰的函数有点像C++/C#/JAVA等语言里类的private函数,只不过C中static函数是对定义它的编译单元而不是类可见。
在C中,static修饰的变量在程序启动时被创建,在程序退出时static变量被销毁。只要static对象对于访问者来说是可见的,那么就可以访问。
C++的情况要复杂一些
static的局部变量与C中一样,作为一个永久、私有存储。如果修饰全局对象(包括函数),那么表示的不是通常理解的:该对象是在该编译单元内可见的,而是表明该对象属于一个无名字的namespace。
作为一种面向对象的语言,在C++中,更多的时候需要考虑的是用static修饰成员。static修饰的成员称为类成员,不是属于任何实例而是属于整个类。至于类成员(数据成员)的初始化与销毁的规则:必须在第一次使用该类对象时初始化,在最后一次使用之后销毁。(题外话:这些static的对象均存放在静态存储上——BSS?)
有一种特殊情况,那就是模板。模板中的static成员对于生成的每个类都是惟一的,也就是说,该类成员在特殊化后(specialized)特定的类中共享。如果需要得到该模板所有生成的类都共享的成员,就要采用其他的技术。为了避免理解上的混乱,我们可以看看这样的例子:
// 类成员在特殊化后(specialized)特定的类中共享
template
class MyTpl
{
private:
static T * aTable;
// ...
};
这里的aTable对于MyTpl类来说都是共享的。而:
// 模板所有生成的类都共享的成员
struct MyStruct
{
static MyStruct * aTable;
};
template
class MyTpl2: public MyStruct
{
// ...
};
这里的aTable是所有MyTpl2,MyTpl2,MyTpl2……等所共享的。
至于访问,可以画出如下访问关系:
Static members of a class An instance of a class
---------------- --------------------
--|static methods|--X--->|Non-static methods|--
| | |<---|--| | |
| ---------------- | X -------------------- |
->|static data | | | |Non-static data |<-
| |<-- -->| |
---------------- --------------------
----->:可访问
--X-->:不可访问
C#与C++类似
几乎可以等同理解。在访问时,应该采用ClassName.m_StaticMember()方式来访问,而在C++中允许aClass.m_StaticMember()方式访问。另一个特殊之处就是:因为Main()函数是static的,因此,要想访问Main()所在类的非静态成员,必须通过该类的一个实例。如:
namespace MySpace
{
public class MyClass
{
public void foo()
{
// ……
}
public static void Main()
{
MyClass a = new MyClass();
a.foo();
// foo(); // Illegal!!!
}
}
}
JAVA也差不多
同样,java中也允许通过实例来访问static成员。
语义层面的共性
除C外,static修饰成员时,代表该成员是类成员,为所有实例所共有,只需要保留一份拷贝。在static成员方法中,因为该方法为所有实例所共有,故不存在this。牢记这条通用规则,就不难理解上述规则了。对于初始化和销毁成员对象,也是如此:作为类成员,必须在第一次使用该类对象时初始化,在最后一次使用之后销毁,这样能保证该类所有实例都能访问这些static成员。这也是static成员作为“类成员”在语义层面上的理解所导出的结论。
至于初始化和销毁,各语言之间在语法上有一些差别,本文不作描述——本文的目的是帮助理解static的作用,而不是语法上的差别,因此对语法不加以讨论;而且本文根本没有深入细节(长叹一声:记忆力太差,根本记不住语法细节,因此每每用到,就要翻书)。
PS:小弟在此抛块砖,有玉尽管砸过来,呵呵。
参考:
The C Programming Language, 2nd edition, by Brian W. Kernighan and M. Ritchie
The C++ Programming Language, special edition, by Bjarne Stroustup
Programming C#, 3rd edition, by Jesse Liberty
Copyleft (C) 2007-2009 raof01.
本文可以用于除商业外的所有用途。此处“用途”包括(但不限于)拷贝/翻译(部分或全部),不包括根据本文描述来产生代码及思想。若用于非商业,请保留此
权利声明,并标明文章原始地址和作者信息;若要用于商业,请与作者联系(raof01@gmail.com),否则作者将使用法律来保证权利。
阅读(8636) | 评论(6) | 转发(0) |