分类: C/C++
2013-02-03 22:48:59
static关键字在C/C++中应用广泛,而且有不同的语义。这篇文章,我主要想探讨一下用static修饰变量的时候,它都有些什么语义,这些变量都有哪些特性。
1.源文件中用static定义全局变量
这个变量只能在这个文件中可见,其它任何文件中对这个变量都是不可见的。而且你不可以用extern把这个变量导出去。
2. 头文件中用static定义一个全局变量
这也是唯一一种能在头文件中定义全局变量的方式。
这种方式定义的变量有一种特性:为每一个包含这个头文件的源文件生成一个特定的变量,每个变量具有与NO.1中的变量具有同样的属性。
3. 定义一个类的static 成员变量
myclass.hxx
class MyClass {
public:
static int mVariable;
};
myclass.cxx
int MyClass::mVariable = 0;
4. 定义一个函数的static变量 (functional scope static variable)
这个static的作用域仅仅是在这个函数内。
以上描述了static变量的使用场合,这里主要是想要介绍一下这些static变量的初始化点。
在C++中,变量不仅仅要被初始化,而且需要一个构造过程。对于POD(plain old data)这类的变量,它们具有C-like的行为,也就是编译器会直接把初始化数据写入.data区域,而不需要额外的代码构造它们。但是对于那些具有自定义构造函数的类型来说,编译器必须安排一个点来调用它们的constructor(构造函数)。那么哪里可以安排代码来调用这些构造函数呢?
对于前三类的static变量,我们很好理解,它们都是在C++程序的初始化过程中被初始化的。对于C++应用程序,它们会在main被调用之前被初始化;对于Windows driver,它们会在driver start过程中被初始化,但是会在Entry function后(重要)。
对于第四类的static变量,我们需要详细的描述一下:
1. 这些变量都保有一块特定的存储空间,这块存储空间都会被置0在程序被装载之后;
2. 如果这些变量是POD类型,那么它们不需要任何额外的构造代码;(或者这类变量会被初始化成特定的值)
3. 对于那些具有特化构造函数的对象,这些构造函数会调用当这个函数第一次被调用时。但是在多线程环境中,构造函数的调用并不保证是线程安全的。(对于g++而言,经过验证,线程安全,而且是由一个spinlock保护的;对于Visual C++而言,它不是线程安全的,而且后面的函数调用根本不会进入static变量的构造函数,而是直接跳过了static变量的构造函数)
所以functional scope static variable是一个很tricky的东西,如果你不确定你在做什么,请小心用它。但是我相信C++下个标准会解决这个问题。