Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1694018
  • 博文数量: 177
  • 博客积分: 9416
  • 博客等级: 中将
  • 技术积分: 2513
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-06 16:08
文章分类

全部博文(177)

文章存档

2013年(4)

2012年(13)

2011年(9)

2010年(71)

2009年(12)

2008年(11)

2007年(32)

2006年(25)

分类:

2007-10-15 10:04:56

在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),否则作者将使用法律来保证权利。
阅读(8588) | 评论(6) | 转发(0) |
给主人留下些什么吧!~~

fera2010-04-10 17:29:16

Keyword "static" has another meaning: when it's used for functions or objects outside all blocks, it means linkage. They all have static storage class. When "static" is used for them, it means internal linkage, and they are only visible in the translation unit.

fera2010-03-26 10:17:37

关键之处在于隐含的this指针。 o 非静态函数需要instance,而静态函数不需要。 o 构造函数特殊之处在于,它从无到有构造一个对象,因此调用它不需要一个instance,也就是不需要this。 o 构造函数分成两个阶段: 1. 分配内存:这是从无到有阶段,该阶段结束,产生一个instance,也即this。 2. 初始化内存:真正调用构造函数的部分。此时已经是对该instance调用构造函数,因此,可以调用任何非静态函数。 o 在静态函数中,只要是通过instance.Func()或者pointer->Func()的方式就可以调用非静态函数,因为显式指定了this。 因此提倡在所有非静态成员函数中显示使用this来使用成员。