c/c++ static关键字详解

一、C语言中Static的作用

C语言 static关键字,表示静态的,主要是用来修饰变量和函数。

1、修饰局部变量

static 修饰局部变量称为静态局部变量

我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅只受此函数控制)。static 关键字则可以很好的解决这个问题。

当 static 修饰局部变量时:

  • 变量的存储区域由变为静态常量区
  • 变量的生命周期由局部调用结束变为程序运行结束
  • 变量的作用域不变。

函数调用开辟栈帧,函数中的局部变量在栈上分配存储空间,当函数执行完毕,函数栈帧销毁,栈空间由系统回收。但在static修饰函数局部变量的时,其修饰的静态局部变量只执行初始化一次,延长了局部变量的生命周期,直到程序运行结束以后才释放,但不改变作用域。

void fun()
{
    
    
	int x = 0; 
	x++;
	printf("%d ", x);
}
 
int main()
{
    
    
	int i = 0;
	while (i < 10)
	{
    
    
		fun();
		i++;
	}
	return 0;
}

运行结果:
1 1 1 1 1 1 1 1 1 1

我们将变量x加上static

static int x = 0; //static修饰局部变量

运行结果会变成: 1 2 3 4 5 6 7 8 9 10

原因是没有 static 时, 函数每调用一次, 变量就会进行一次初始化值为 0。当由static修饰了局部变量x,令局部变量x变成静态的,使得每次fun()函数结束时局部变量x都不销毁,再次进入fun()函数时,则保留原有数值运行,初始化语句只会被执行一次所以值会一直累加,因此x++数值越来越大。

其本质是:

普通的局部变量创建后是放在栈区中,这种局部变量进入作用域时创建,出了作用域就销毁;但static修饰后的局部变量则放在静态区中,它改变了局部变量的存储位置,从而使得变量的生命周期延长,延长至程序结束才销毁。变量的作用域不变

注意:如果static变量定义时未赋初值,编译时会自动将其赋值为0

2、修饰全局变量

static 修饰全局变量称为静态全局变量

static修饰全局变量时,会改变全局变量的链接属性,从而使得全局变量的作用域变小

全局变量:在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。

  • 全局变量的作用域十分广,只要在一个源文件中定义全局变量后,这个程序中的所有源文件、对象以及函数都可以调用,生命周期更是贯穿整个程序。一个源文件中的全局变量想要被另一个源文件访问使用时,就需要进行外部声明(用extern关键字进行声明)。
  • 当全局变量在一个源文件中用statci关键字修饰后,其他源文件无法访问这个全局变量

其本质是:
全局变量本身是具有外部链接属性的,在A文件中定义的全局变量,在B文件中可以通过【链接】来使用(用extern关键字进行声明);但如果全局变量被static修饰,那这个外部链接属性就会被修改成内部链接属性,此时这个全局变量被禁止在其他文件中使用,就只能在自己的源文件中使用;

当 static 修饰全局变量时:

  • 变量的存储区域在全局数据区的静态常量区
  • 变量的作用域由整个程序变为当前文件。(extern声明也不行)
  • 变量的生命周期不变。

3、修饰函数

static 修饰函数称为静态函数

static修饰函数的与修饰全局变量十分相似,修饰函数时会改变函数的链接属性,从而使得函数的作用域变小

  • 一个源文件中的函数,可以被其他源文件中的函数访问(同样需要extern关键字声明)。但当一个源文件中的函数被static修饰成静态函数后,其他源文件无法访问这个静态函数。
  • 静态函数本质和静态全局变量很像:函数本身也是有外部链接属性的,被static修饰后,函数的外部链接属性被修改成内部链接属性,使得这个函数只能在自己的源文件内被使用,禁止在其他源文件中使用,因此静态函数的作用域变小了。

当 static 修饰函数时:
函数的作用域由整个程序变为当前文件。(extern声明也不行)

二、C++中Static的使用

1、类的静态数据成员

• 静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
• 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。语句int Myclass::Sum=0;是定义静态数据成员;
• 静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
• 因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
• 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
<数据类型><类名>::<静态数据成员名>=<值>
• 类的静态数据成员有两种访问形式:
<类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
• 静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;

2、类的静态成员函数

• 类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致 了它仅能访问类的静态数据和静态成员函数。由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;
• 出现在类体外的函数定义不能指定关键字static;
• 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
• 非静态成员函数可以任意地访问静态成员函数和静态数据成员;
• 静态成员函数不能访问非静态成员函数和非静态数据成员;
• 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
<类名>::<静态成员函数名>(<参数表>)
调用类的静态成员函数。

猜你喜欢

转载自blog.csdn.net/m0_46208463/article/details/140628413