static 关键字用法

时间:2023-01-31 17:37:57

在C或C++中,static主要用作定义全局静态变量、定义局部静态变量、定义静态函数。

所谓“静态”,打个比方就是,告诉编译器:“我想静静的做个美男子”,给我在内存中一席之地,我在我自己所在的作用域(C文件)中,从一而终(进程开始到结束),别人休想打扰我(别的文件不能直接调用他),即便外部有很多跟我同名同姓的也无所谓,因为我的名字不会出现在江湖(不是严格的全局变量)。、

使用场景1-定义全局静态变量:当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其他的全局变量的存储地点并没有区别,都是在.data段(已初始化)或者.bss段(未初始化)内,但是它只在定义它的源文件内有效,其他源文件无法访问它。所以,普通全局变量穿上static外衣后,它就变成了新娘,已心有所属,只能被定义它的源文件(新郎)中的变量或函数访问。

示例程序,在file1.h中定义如下:
#include <stdio.h>  

void printStr();
我们在file1.c中定义一个静态全局变量hello, 供file1.c中的函数printStr访问.
#include "file1.h"  

static char* hello = "hello cobing!";

void printStr()
{
printf("%s\n", hello);
}

file2.c是我们的主程序所在文件,file2.c中如果引用hello会编译出错
file2.c:6: 错误:‘hello’ 未声明 (在此函数内第一次使用)
file2.c:6: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
file2.c:6: 错误:所在的函数内只报告一次。)

如果我们将file2.c改为下面的形式:
#include "file1.h"  
  int main()  {      printStr();      return 0;  }  
则会顺利编译连接。

 二,static局部变量

      普通的局部变量在栈空间上分配,这个局部变量所在的函数被多次调用时,每次调用这个局部变量在栈上的位置都不一定相同。局部变量也可以在堆上动态分配,但是记得使用完这个堆空间后要释放之。

       static局部变量中文名叫静态局部变量。它与普通的局部变量比起来有如下几个区别:

           1)位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见3)),所以它虽然是局部的,但是在程序的整个生命周期中存在。

           2)访问权限:静态局部变量只能被其作用域内的变量或函数访问。也就是说虽然它会在程序的整个生命周期中存在,由于它是static的,它不能被其他的函数和源文件访问。

           3):静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。这个比较好理解,每次函数调用静态局部变量的时候都修改它然后离开,下次读的时候从全局存储区读出的静态局部变量就是上次修改后的值。
以下是一些示例程序:


file1.h的内容和上例中的相同,file1.c的内容如下:
#include "file1.h"  

void printStr()
{
int normal = 0;
static int stat = 0; //this is a static local var
printf("normal = %d ---- stat = %d\n",normal, stat);
normal++;
stat++;
}

为了便于比较,我定义了两个变量:普通局部变量normal和静态局部变量stat,它们都被赋予初值0;
file2.c中调用file1.h:
#include "file1.h"  

int main()
{
printStr();
printStr();
printStr();
printStr();
printf("call stat in main: %d\n",stat);
return 0;
}
这个调用会报错,因为file2.c中引用了file1.c中的静态局部变量stat,如下:
file2.c: In function ‘main’:
file2.c:9: 错误:‘stat’ 未声明 (在此函数内第一次使用)
file2.c:9: 错误:(即使在一个函数内多次出现,每个未声明的标识符在其
file2.c:9: 错误:所在的函数内只报告一次。)

编译器说stat未声明,这是因为它看不到file1.c中的stat,下面注掉这一行:、

#include "file1.h"  

int main()
{
printStr();
printStr();
printStr();
printStr();
// printf("call stat in main: %d\n",stat);
return 0;
}
normal = 0 ---- stat = 0
normal = 0 ---- stat = 1
normal = 0 ---- stat = 2
normal = 0 ---- stat = 3

运行如上所示。可以看出,函数每次被调用,普通局部变量都是重新分配,而静态局部变量保持上次调用的值不变。

需要注意的是由于static局部变量的这种特性,使得含静态局部变量的函数变得不可重入,即每次调用可能会产生不同的结果。这在多线程编程时可能会成为一种隐患。需要多加注意。


三,static函数
              相信大家还记得C++面向对象编程中的private函数,私有函数只有该类的成员变量或成员函数可以访问。在C语言中,也有“private函数”,它就是接下来要说的static函数,完成面向对象编程中private函数的功能。

            当你的程序中有很多个源文件的时候,你肯定会让某个源文件只提供一些外界需要的接口,其他的函数可能是为了实现这些接口而编写,这些其他的函数你可能并不希望被外界(非本源文件)所看到,这时候就可以用static修饰这些“其他的函数”。

           所以static函数的作用域是本源文件,把它想象为面向对象中的private函数就可以了。

下面是一些示例:

file1.h如下:

#include <stdio.h>  

static int called();
void printStr();
file1.c如下:

#include "file1.h"  

static int called()
{
return 6;
}
void printStr()
{
int returnVal;
returnVal = called();
printf("returnVal=%d\n",returnVal);
}

file2.c中调用file1.h中声明的两个函数,此处我们故意调用called():

编译时会报错:

file1.h:3: 警告:‘called’ 使用过但从未定义
/tmp/ccyLuBZU.o: In function `main':
file2.c:(.text+0x12): undefined reference to `called'
collect2: ld 返回 1

因为引用了file1.h中的static函数,所以file2.c中提示找不到这个函数:undefined reference to 'called'

下面修改file2.c:

#include "file1.h"  

int main()
{
printStr();
return 0;
}
 static函数可以很好地解决不同原文件中函数同名的问题,因为一个源文件对于其他源文件中的static函数是不可见的。