static关键字大家肯定都不陌生,只要你写过c++,java,c#,或者是js,通常情况下,你肯定要使用到static关键字
一般情况下,我们使用它都是用在类中的函数上,或者是函数内的变量,或者类的全局变量,在面向对象的语言当中,使用static无非就为了以下几点
内部变量保存、方法的静态调用、变量的静态调用
比如我们写C++的时候
class abc {
public:
static int c;
static void aaa()
{
static int tt = 1;
cout <<tt << endl;
tt++;
}
};
int abc::c = 12;
int main()
{
abc::aaa();
cout << abc::c << endl;
abc::aaa();
}
这个一看一目了然,静态调用abc类中方法aaa、变量c的时候,都是直接用类名调用,并没有声明对象
变量tt的使用方式,是static最常用的方法,保存变量
上述代码输出
但在没有类概念的C中,static变量有什么用呢?
一、C语言中static的作用
- 保存局部变量
这一点上,C和C++还有其他语言基本是一样的
如果在函数内部使用static 修饰变量,则这个变量,就好像全局变量一样,每次调用到这个函数时候,这个变量还能保持上一次的值。但是又和全局变量不一样,本函数外部函数又不能调用它,例如
#include <stdio.h>
void abc() {
static int a = 0;
printf("%d\n", a);
}
int main()
{
abc();
abc();
}
如上例,如果没有static 的修饰a的话,则调用两次abc(),就会输出两次0
因为变量脱离作用域,就失效了,第二次调用等于重新给a赋值,但是用了static就不一样了,static可以保存局部变量,让局部变量不失效,所以,上例输出为
- static修饰的变量和函数,表示这个变量、函数只能被当前文件所链接
以上这个性质的意思是说,如果你的变量、函数被static修饰的话,这个函数或者变量还在其他文件当中,那么在编译链接时,链接将无法实现,举个例子说明,就把上例改一改,把函数abc移动到一个新的文件b.c中
#include <stdio.h>
int xxx = 999;
void abc() {
static int a = 0;
printf("%d\n", a);
a++;
}
然后在c.c中调用他
#include <stdio.h>
int main()
{
extern int xxx;
printf("%d\n", xxx);
abc();
abc();
}
你要是按上面代码编译的话,没问题,可以成功。
但是b.c中的abc函数、变量xxx,如果用static修饰的话
#include <stdio.h>
static int xxx = 999;
static void abc() {
static int a = 0;
printf("%d\n", a);
a++;
}
再编译,就会报错了
error LNK2019: 无法解析的外部符号 abc,该符号在函数 main 中被引用
error LNK2001: 无法解析的外部符号 xxx
不过,如果你把b.c排除在编译外,把他当成引用文件在,c.c中include他
#include <stdio.h>
#include "b.c"
int main()
{
extern int xxx;
printf("%d\n", xxx);
abc();
abc();
}
这就没问题了,因为最终他们就合成一个文件了,编译就成内部链接了
二、 static的本质
先看一个例子
#include <stdio.h>
char* a = "aaaaaa";
int main()
{
char* b = "bbbbbb";
printf("%s\n",b);
static char* c = "cccccc";
printf("%s\n", a);
printf("%s\n", c);
}
上述代码输出
aaaaaa
bbbbbb
cccccc
这不是重点,重点在汇编里
从上面可以看到,函数中的局部b,静态变量c,和全局变量a,在读取方式上并无区别
所以说,static变量,只不过,他只是在编译期间有效,在编译后,它将以全局变量方式存在,但在编译时,编译器对变量作用域判断时,它又和局部变量一样只能存在于函数作用域内