static意为静止的、不变的,如其字意,在C语言中,关键字static的出现将改变变量的存储区域和作用域。static作为关键字还广泛出现在各种编程语言中,不管是C、C++、C#、JAVA、VB,还是其他高级计算机语言如FORTRAN、ALGOL、COBOL、BASIC、LISP等语言中,都有static的身影,只是有着不同的作用。本文将对C/C++中的static关键字做比较全面的说明,作为小结。
(注:在写本篇学习笔记时,本人学习和参考了网络文章,并做了借鉴,感谢各位前辈的分享。如果本文对您有所帮助,您可以随意分享,如果发现文中有误,也请指教,谢谢。本文用到的调试工具:C-free 5.0,操作系统:Windows 7)
在C/C++中,static作为关键字的作用为:
1、修饰局部变量;
2、修饰全局变量;
3、修饰全局函数;
4、修饰成员变量或者成员函数;(C++)
1、修饰局部变量:
void fun()
{
int i=10;
static int j=10;
}
在修饰局部变量的时候,static改变了变量的存储区域。局部变量的定义和声明默认情况下是auto修饰的,这也是我们在C语言程序中很少看到auto的原因。
auto修饰的变量存储在栈中,属于动态存储类别,占用动态存储空间,函数调用结束后自动释放;aoto变量如果没有初始化,其值不可预知,可能是被分配的这段内存中的任何值。
而static修饰的变量分配在静态区存储区,在程序整个运行期间一直存在;static变量如果没有初始化,则默认为0。
auto和static修饰的变量作用域相同,但生存周期不同。
2、修饰全局变量:
如果有一个文件fileA.c:
int i=10;
static int j=20;
void funA()
{
printf("i=%d\n",i); // 打印结果为“i=10”
printf("j=%d\n",j); // 打印结果为“j=20”
int i=30;
int j=40;
printf("i=%d\n",i); // 打印结果为“i=30”
printf("j=%d\n",j); // 打印结果为“j=40”
}
另一个文件fileB.c:
void funB()
{
printf("i=%d\n",i); // 正确,i为普通全局变量,可被操作,打印结果为“i=10”
printf("j=%d\n",j); // 错误,j为静态全局变量,只能作用域fileA
}
在修饰全局变量的时候,static改变了变量的作用域。全局变量的定义和声明在默认情况下是extern修饰的,这也是我们在C语言程序中很少看到extern的原因。
如上例所示,i为一般的全局变量,可在fileB中操作,而j为静态全局变量,只能作用于fileA中,fileB中不可见。
作为全局变量,如果没有被初始化,不管是static还是extern,则其值都默认为0。
在这里,我还想说明一下fileA中出现的变量隐藏,C语言的初学者需要特别在意,全局变量的作用域比局部变量大,但是局部变量的优先级比全局变量高,如果在一个函数块中声明了一个与全局变量名相同的变量,那么全局变量将被隐藏。
3、修饰全局函数:
如果有一个文件fileA.c:
void funA1()
{
}
static void funA2()
{
}
另一个文件fileB.c:
int main()
{
funA1(); // 正确,i为普通全局变量,可被操作,打印结果为“i=10”
funA2(); // 错误,静态全局变量,只能作用域fileA
return 0;
}
在修饰全局函数的时候,static改变了全局函数的作用域。
如上例所示,被关键字static修饰的函数只作用于本文件,其他文件不可被调用。
以上都是static在C语言中的用法,下面我们来看下C++对static用法的扩展。
4、修饰成员变量或者成员函数:
class EnemyTarget
{
public:
EnemyTarget()
{
++numTargets;
}
EnemyTarget(const EnemyTarget &)
{
++numTargets;
}
~EnemyTarget()
{
--numTargets;
}
static size_t numberOfTarget()
{
return numTargets;
}
bool destroy();
private:
};
size_t EnemyTarget::numTargets;
C++重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最大区别, 也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实例, 就可以用到静态数据成员. 在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性. 这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义. 因为它是对整个类来说是唯一的, 因此不可能属于某一个实例对象的。(针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针。)
在上例中,静态数据成员numTargets就是用来统计产生的对象个数的。
另外,在设计类的多线程操作时,由于POSIX库下的现场函数pthread_create()要求是全局的,普通成员函数无法直接作为线程函数,可以考虑用static成员函数做现场函数。