【C语言】关键字static的初步剖析

在初识C语言的过程中,static由于使用的灵活性,使我在了解这个关键字的时候十分苦恼,因此我决定来写一篇博客来帮助自己和不懂的小伙伴能更好的理解static这个关键字。如有错误,请大家指正。

在C语言中static有两个作用,其一是修饰变量,其二则是修饰函数。​​​​​

目录

变量

1.局部变量

2.全局变量

函数

总结

作者结语


变量

1.局部变量

平常的局部变量想必大家都非常熟悉,具有局域临时性。即在函数调用开辟空间时并初始化,函数结束释放空间并初始化。

而局部变量存储在栈区上,使用完毕后会立即释放。(为了让大家可以理解的轻松些,下面附上C程序地址空间的图。)

静态局部变量也就是由static修饰定义的变量,存储于进程的全局数据区,也就是图中的未初始化全局,已初始化全局和静态数据区域。

其特点有三:

1)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化。

2)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0。

3)它始终驻留在全局数据区,直到程序运行结束。但作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。

而其作用是更改局部变量的生命周期。因为静态局部变量存储在全局数据区,当静态局部变量离开作用域后,并没有被销毁。当该函数再次被调用的时候,该变量的值为上次函数调用结束时的值。

让我们用一段代码来理解它的作用:

#include<stdio.h>
void test1()
{
	int i = 0;
	i++;
	printf("i=%d\n", i);
}
void test2()
{
	static int i = 0;
	i++;
	printf("i=%d\n", i);
}
int main()
{
	for (int i = 0; i < 5; i++)
	{
		test1();
		test2();
	}
	return 0;
}

在vs2022中运行结果如下:

test1
i=1
i=1
i=1
i=1
i=1
------------
test2
i=1
i=2
i=3
i=4
i=5

在调用test1函数时 ,由于i为局部变量,在test1函数执行结束后,其生命周期也就结束了,在每次调用test1函数时,i都会被赋值为0,因此输出结果为5个1;而局部变量i经static修饰后其生命周期变长,在离开作用域时并不会被销毁,当test2函数调用时,变量i的值为上次函数结束调用结束时的值,因此输出结果为1-5。

可见静态局部变量i在运行的过程中并没有被释放!!!

这也恰巧说明了static修饰的局部变量更改局部变量的生命周期。

但是请注意static并没有改变作用域!!!

我们用以下代码来证明:

代码中我们可以看到当fun函数调用完后,再次给a赋值发生了报错,a无法再使用了。所以static只是改变了局部变量的生命周期而并没有改变其作用域。且static修饰的局部变量而并非全局变量。

2.全局变量

与静态局部变量相似,静态全局变量就是在全局变量前加上关键字static修饰,该变量就被定义为一个静态全局变量。未经初始化的静态全局变量会被程序自动初始化为0。

静态全局变量的优点:

1)静态全局变量只能在本文件中有效且不能被其他文件所用。

2)其他文件中可以定义相同名字的变量且互不冲突。

为了让大家可以更加容易理解优点1,让我们先了解一下多文件使用:

(1)为什么使用多文件?

当我们写代码时,难免会碰到代码多,且逻辑复杂等情况,这时如果将代码全写在一个文件内,在他人阅读我们的代码时会造成一定的困难,代码的可读性低,代码十分臃肿。并且有多个函数的声明,定义,还有引用头文件,定义之类的东西,在一个文件里太过于复杂,且容易遗漏,所以衍生出来了头文件。

(2)多文件使用的注意事项

一般会有一个头文件(.h)和一个main.c和若干个源文件(.c)文件。头文件中主要用来所有变量的声明,所有函数的声明,#define,类型typedef,struct等等。main.c主要用于实现代码逻辑,其他.c用于实现头文件中声明函数的功能。但是请注意,它们都需要引用自己创建的头文件!!!(例:#include"test.h")

好了,以上就是对于多文件使用的科普,所以话不多说,我们还是接下来用例子来证明优点1吧:

全局变量的跨文件访问:

 从上面三张图我们可以知道,在test.c中定义的全局变量g_val可以再main.c中被使用,因此全局变量是可以进行跨文件访问的!!!

那么static修饰的静态全局变量呢???

我们可以看到在全局变量g_val前加上static,就出现了一系列报错,test.c中定义的全局变量无法在main.c中被使用了!这也恰好证明了static修饰的全局变量不能被外部其他文件直接访问!!!

 看到这可能大家会有些疑惑,你不是说静态全局变量只能在本文件内被访问吗,可你这不只证明了静态全局变量不能被跨文件访问,你是不是蒙我们啊?别急,接下来我们就来证明这个结论:

 我们将test函数里面加上一行代码,看看g_val能不能被打印出来,结果是可以的。所以,静态全局变量可以在本文件内被访问。

但是请注意由于静态全局变量不能跨文件访问,在运行代码时需要将main.c中对g_val的打印需要注释掉!!!

虽然不能直接访问,但是也可以采用间接访问的方式:

 相信通过这些例子,大家也应该可以理解静态全局变量只能在本文件中有效且不能被其他文件所用这个优点了。全局变量是具有外部链接属性的,如果全局变量被static修饰,外部链接属性就变成了内部链接属性。其他源文件就没法通过链接找到这个内容。

函数

在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

其优点与静态全局变量近似:

1)静态函数不能被其它文件所用。

2)其它文件中可以定义相同名字的函数,不会发生冲突。

话不多说,上例子!

 从上一个例子中我们可以看到原先这个代码是可以编译过去的,但是如果在函数前加上static那么就会直接形成报错。

 我们可以看到有一个叫做LNK1120,这个错误叫做链接器错误,是程序在进行编译链接形成和执行程序时,链接错误,无法解析到test函数。

同样的,虽然不能直接访问,也是可以采用间接访问的方式:

 由代码所示,在test.c中定义test_helper函数,并在test.h中声明该函数,最后在main.c中调用该函数,是没问题的。(但是请注意,无关的代码需要注释掉!!!

函数是具有外部链接属性的,其他源文件想使用函数,需要正确的声明就可以。但是函数被static修饰,外部链接属性就变成了内部链接属性,这个时候函数只能在自己所在的.c文件内部使用,不能在外部使用。

(补充:外部链接属性 - 所有的其他文件都能找到 内部链接属性 - static 无链接属性 - 局部变量)

以上也就证明了静态函数不能被其他文件所使用,并且实现了静态函数的间接访问。

总结

static是一个很有用的关键字,因为其独特的优点,合理地使用static可以形成一个良好的编码风格。static也因其特性,也是一个对于项目维护和提供安全保证上一个强有力的帮手。作为一名程序员,养成良好的编码风格,也是十分重要的!!!

作者结语

首先非常感谢可以看到这里的小伙伴们,笔者因为是第一次写博客且是一个小白,在对于static关键字的理解上可能有些不到位的地方。如有错误,还请指正!

                                                               再次表示感谢!!!

猜你喜欢

转载自blog.csdn.net/m0_67867172/article/details/125008937