学过C或者C++程序设计语言的同学一定对关键字static不是很陌生,但是是否对其非常熟悉,熟练掌握其用法,把握其本质和精华,我想大部分同学未必如此。static是C语言32个关键字中的一员,造成大家对它掌握不是很深刻的原因我想可能是在平时学习或者实际编程中对它用得较少。为了全方位揭开static这个关键字的庐山真面目,下面我结合若干文献做一小结。
一、static在C语言中的作用
static作为关键字,它可以用来修饰变量和函数,在C语言中其作用总体来说有两个。其一是起到信息隐藏的作用,即将变量或者函数的作用域限制在本文件中,即使在别的文件中使用extern关键字对其进行声明仍然不能访问它,这样做的好处好处是不同程序员在不同文件中编写的程序不用担心自己定义的变量或函数名与其它文件中的变量或者函数名同名。这样就可以保证多文件编译的正确进行。Static关键字在C语言中的第二个作用是表示变量的存储方式,即静态存储,就是说程序在运行期间占有固定的存储空间。这种方式一般用于常见于修饰变量。用static修饰的变量是静态变量,又分为静态全局变量和静态局部变量。它们都存储在内存的静态存储区中,静态全局变量的作用域从变量定义开始到文件结尾处结束,静态局部变量的作用域仅仅限于定义它的函数内部,由于其存储在静态存储区,函数调用结束后变量的值不会丢失而是保留上一次函数调用结束时的值。这样实际上起到了持久保存变量内容的作用。
二、举例说明其作用
1、信息隐藏作用的举例说明
假设我们需要同时编译两个文件,其中A文件用到了B文件中定义的变量和函数,我们只需要在A文件中对B文件中定义的变量或函数用extern声明一下就可以了,这样就扩展了变量的作用域。但是如果在B文件中定义变量或者函数时用了static修饰符,即限定其作用域为所在的文件,那么在别的文件就不可能再使用这些变量了。且看下面两个程序:
/*文件a.c*/
#include<stdio.h>
char a='A';
void msg()
{
printf("hello/n");
}
/*文件main.c*/
#include<stdio.h>
int main()
{
extern char a;
extern void msg();
printf("%c",a);
msg();
return 0;
}
同时编译这两个源文件,程序运行的结果是:Ahello
现在我们修改a.c中变量a的定义为static char a=’A’;然后重新编译,发现ok,然后再链接,出现问题如下:
--------------------Configuration: a - Win32 Debug--------------------
Linking...
main.obj : error LNK2001: unresolved external symbol "char a" (?a@@3DA)
Debug/a.exe : fatal error LNK1120: 1 unresolved externals
执行 link.exe 时出错.
a.exe - 1 error(s), 0 warning(s)
-----------------------------------------------------------------------
提示的意思:a是一个不确定的外部变量。这是因为a是一个静态变量,其作用域只限于定义它的文件,尽管在main.c中也用extern对其进行了声明,但这中声明是无效的。
2、表示变量的存储方式,持久保存变量内容的作用举例说明
且看下面程序:
------------------------------------------------------------------------
#include <iostream>
using namespace std;
static int j;
void fun1()
{
j=0;
j++;
}
void fun2()
{
static int i=0;
i++;
}
int main()
{
int k;
extern j;
for(k=0;k<10;k++)
{
fun1();
fun2();
}
return 0;
}
----------------------------------------------------------------------
这个程序完毕,i和j的值是多少呢?程序运行后i的值为10,j的值为1。(可以在main函数for循环后加个输出语句,在fun2()中也加个输出语句进行检测)
这个程序很好的说明了静态局部变量(如i)其值在函数调用结束后不会丢失,在下一次调用该函数时变量还保留了上一次函数调用结束是的值。
三、关于静态局部变量的几个说明
1、静态局部变量在编译时赋初值,即只赋值一次,在程序运行时其已有初值,在以后每次调用函数时不用重新赋初值而只是保留上次函数调用结束时的值。自动变量的赋初值不是在编译时进行,而是在函数调用时进行的,每调用一次重新给一次初值。
2、如果在定义静态局部变量的时候不赋初值,编译时系统会自动给其赋初值0(对整型变量)或空字符(对字符变量)。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘/0’太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是‘/0’。不妨做个小实验验证一下。
----------------------------------------------------------------
#include<stdio.h>
int a;
int main()
{ int i;
static char str[10]="hello";
printf("%d,begin#%s#end/n",a,str);
return 0;
}
------------------------------------------------------------------
程序的运行结果为:0,begin#hello#end
3、静态局部变量在函数调用结束后仍然存在,但是其他函数是不能引用它的。
此外,在C++中,使用static可以使一个对象的某些属性成为类属性,即可以让多个对象共享的属性。如下面定义的类Number中将count声明为静态,会为这个属性分配一段内存用于由这个类实例化的所有对象,这个类的所有对象使用count时都使用相同的内存位置。实际上每个类的count对象只有一个副本,它由该类的所有对象共享。
-------------------------------------------------------------------
public class Number{
static int count;
public method(){}
}
-------------------------------------------------------------------
值得特别注意的是,如果static用于修饰类的成员函数,由于这个函数属于整个类的所有对象共有,因此不能接受this指针,它只能访问类的static成员变量。
参考文献:
[1]百度文库static的作用 http://wenku.baidu.com/view/d130ca2f0066f5335a8121ed.html
[2]谭浩强 C程序设计(第二版)
[3]Matt Weisfeld 著,张雷生,刘晓冰 等译 《写给大家看的面向对象编程书》P50-P51
注:引用请注明出处http://blog.csdn.net/collier/archive/2010/09/02/5859626.aspx