C语言static关键字
- C语言之static
- 1、什么是static?
- 2、static的意义
- 3、C/C++ static的属性
- 4、static的用法
- 4.1、static修饰局部变量例程
- 4.2、static修饰全局变量例程
- 4.3、static修饰函数例程
- 5、结束语
C语言之static
前言:
先简单了解下“三大区”,在C/C++程序中:
a、栈区:存放局部变量/形式参数等,具有临时属性的变量
d、堆区:存放动态内存所分配的数据,如malloc、free、realloc等
e、静态区:存放全局变量/static所修饰的静态(局部)变量等
如图所示:
1、什么是static?
概念: 是C语言中很常用的修饰符,它被用来控制变量的存储方式和可见性。
作用:
a、static静态变量声明符。
b、static 关键字不仅可以用来修饰变量,还可以用来修饰函数。
注意:
a、静态变量的存储方式与全局变量一样,都是静态存储方式。
b、静态变量属于静态存储方式,但是属于静态存储方式的变量却不一定就是静态变量。
c、在使用 static 关键字修饰变量时,我们称此变量为静态变量。
d、在声明它的程序块,子程序块或函数内部有效,值保持不变,在整个程序期间分配存储器空间,编译器默认值0。
2、static的意义
当一个函数内部定义了变量,在程序执行到它的定义处时,编译器会它在栈上分配空间,由局部变量的性质可知,函数在栈上分配的空间在此函数执行结束时会释放掉(生命周期/作用域)。
这时我们对这个变量的操作就多了一些约束: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制,而是整个工程都可以反访问了,特别是局部变量名一致时,优先级局部变量所以容易冲突)。
那么就需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。
3、C/C++ static的属性
静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。
这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的main()函数前的全局数据声明和定义处。
静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的“尺寸和规格”,并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。
static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态
数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。
优势:
可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。
小结:
静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
非静态成员函数可以任意地访问静态成员函数和静态数据成员;
静态成员函数不能访问非静态成员函数和非静态数据成员;
4、static的用法
语法:
static修饰变量 + 类型 + 变量名 + 初始化
如:statuc int a = 1
static修饰函数 + 函数类型 + 函数名(参数)
如:static int add(int x, int y)
说明:
static常见用法:
1)修饰局部变量
2)修饰全局变量
3)修饰函数
4.1、static修饰局部变量例程
说明:
a、这时的局部变量就是静态的局部变量
b、一个普通的局部变量进入函数创建,出函数销毁,但是被static修饰后,进入函数已经创建好了,出函数时候也不再销毁,多次调用函数时,共享一个变量
c、理解为:生命周期变长了,但是作用域不变,只能在局部范围内使用
d、本质:普通的局部变量是存放在栈区上的,但是被static修饰后,是存放在静态区的,静态区的变量生命周期和全局变量的生命周期一样
/*例程1*/
#include <stdio.h>
//void test()
//{
// int i = 1;//局部变量
// //这里的i与main函数中的i意义不同
// i++;
// printf("%d\n",i);//2 2 2 2 2
// //输出一次i,则生命周期结束一次
//}
void test()
{
static int i = 1;//static修饰局部变量
//使得这里的i,改变局部变量的属性
i++;
printf("%d\n", i);//2 3 4 5 6
}
int main()
{
int i = 0;
while (i < 5)
{
test();//函数独立
i = i + 1;
}
return 0;
}
4.2、static修饰全局变量例程
说明:
a、结合test011.c理解
b、全局变量具备外部链接属性的,这种属性决定了全局变量在多个文件中相互使用
c、全局变量在其他源文件内部均可以使用,但是经过static修饰后,使得其变成内部链接属性,其他源文件就不能链接到这个静态的全局变量了。可理解为:公有变私有
/*例程2*/
#include <stdio.h>
//int g_val = 2023;//定义一个全局变量
//当想使用在同工程下的.c文件的全局变量时,需要用extren声明才可以使用
extern int g_val;
//extern 相当于告诉编译器:g_val变量来自工程下的其他文件
void test()
{
printf("test( ): %d\n",g_val);
}
int main()
{
printf("%d\n",g_val);
test();
return 0;
}
/*test011.c*/
int g_val = 2023;
//static int g_val = 2023;
//static修饰全局变量的时候,将外部链接属性变成了内部链接属性
// 使得g_val只能在当前.c源文件中使用了,不能在其他.c文件中使用了
// 理解为:改变了全局变量的作用域
//本质:在语法层面进行了限制,并未改变存放的区域
4.3、static修饰函数例程
说明:
a、结合test011.c理解
b、static修饰int add(int x, int y)函数,使得函数只能在函数自己所在的源文件中使用,不能在其他源文件中使用
c、函数也是具备外部链接属性的,这种属性决定了函数是可以跨文件使用的
d、static修饰函数是把函数外部链接属性改变为内部链接属性,使得函数只能在当前.c文件中使用
e、本质上:static是将函数的外部链接属性变成了内部链接属性(与修饰全局变量,大相近同)
#include <stdio.h>
//函数的定义
//int Add(int x,int y)
//{
// return x + y;
//}
//函数的外部定义/引用
//借助extern进行声明来自外部的函数
extern int Add(int x,int y);
int main()
{
int a = 3;
int b = 5;
int c = Add(a,b);//函数的调用
printf("%d\n",c);//8
return 0;
}
/*test011.c*/
//static修饰函数
//函数也是具备外部链接属性的
//这种属性决定了函数是可以跨文件使用的
//static修饰函数是把函数外部链接属性改变为内部链接属性
//使得函数只能在当前.c文件中使用
int Add(int x, int y)
{
return x + y;
}
小结:
a、static修饰局部变量时,改变了局部变量的生命周期(本质是改变了变量的存储类型)
b、全局变量在其他源文件内部均可以使用,但是经过static修饰后,使得其变成内部链接属性,其他源文件就不能链接到这个静态的全局变量了。可理解为:公有变私有
c、static修饰函数与修饰全局变量十分类似,因为函数与全局变量都具备外部属性链接的特性。
5、结束语
总体来说;
static是一个非常有用的关键字,能够帮助程序员在编写程序时,使用恰当能够大大提高程序的模块化特性,有利于扩展和维护。
因此,编写程序时应该充分发挥static的作用,并合理地搭配其他语句和特性使用,以便更好地保证程序的正确性、可靠性以及严谨性。