当前位置:   article > 正文

C:关于static 和 extern 关键字的介绍-学习笔记

C:关于static 和 extern 关键字的介绍-学习笔记

目录

1、作用域与生命周期

1.1 作用域

1.2 生命周期

1.3 变量的作用域和生命周期之间的关系

2、static 和 extern

2.1 static 修饰局部变量:

2.2  static 修饰全局变量(包含extern的作用):

2.3 static修饰函数:

结语:


本篇文章将介绍两个关键字 static 、extern的作用


1、作用域与生命周期

在介绍 static 和 extern之前,我们需要先了解:作用域与生命周期

1.1 作用域

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效(可用)的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

  1.  局部变量的作用域是变量所在的局部范围。
  2. 全局变量的作用域是整个工程(项目)。

该怎么理解呢?举个例子

  1. int main()
  2. {
  3. {
  4. int a = 10;
  5. printf("a1 = %d\n", a);
  6. }
  7. // printf("a2 = %d\n", a);
  8. return 0;
  9. }

a1可以打印,a2不可以打印

从上图我们可以看到a2显示是未声明的标识符,是因为a2并不在int a = 10 所在的大括号内。

a只能在局部范围内使用。所以a的作用域就是大括号范围。

因此我们可以知道局部变量的作用域就是变量所在的局部范围。

全局变量的作用域我们也就可以推算出来,全部变量的作用域是整个工程。

  1. int a = 10;//全局变量
  2. void test()//子函数
  3. {
  4. printf("a3 = %d\n", a);
  5. }
  6. int main()//主函数
  7. {
  8. {
  9. printf("a1 = %d\n", a);
  10. }
  11. printf("a2 = %d\n", a);
  12. return 0;
  13. }

不管a在哪里,只要在该工程内,都是可以使用的,所以全局变量的作用域是整个工程。

1.2 生命周期

生命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段。

  1.  局部变量的生命周期是:进入作用域变量创建,生命周期开始,出作用域生命周期结束。
  2.  全局变量的生命周期是:整个程序的生命周期。 

这个该怎么理解呢?

首先是关于局部变量生命周期的理解:

  1. int main()
  2. {
  3. {
  4. int a = 10;
  5. printf("a1 = %d\n", a);
  6. }
  7. // printf("a2 = %d\n", a);
  8. return 0;
  9. }

图解: 

从上图我们可以看到,当a出了大括号范围后,a就不能使用了

所以,当a创建的时候,生命周期开始,当a出作用域后就没法用了,所以被销毁,也就是生命周期结束。

所以局部变量的生命周期是:进入作用域变量创建,生命周期开始,出作用域生命周期结束

所以我们也可以认为全局变量的生命周期就是整个程序的生命周期。

1.3 变量的作用域和生命周期之间的关系

变量的作用域和生命周期密切相关,但又有所不同。

作用域决定了变量在程序中的哪些部分可以被访问和操作,而生命周期则决定了变量存在和有效的时间段。

一般来说,变量的作用域会影响其生命周期。

当一个变量具有局部作用域(例如在函数内部定义的非静态变量)时,它的生命周期通常与函数的执行相关。函数被调用时变量被创建,函数执行结束后变量被销毁,其生命周期相对较短。

而具有全局作用域的变量,或者在函数内部使用 static 关键字修饰的变量,其作用域通常更广,生命周期也更长,从程序开始运行一直到程序结束。

例如:

  1. void fun()
  2. {
  3. int a = 10; // 局部变量,作用域在 fun 函数内,生命周期随函数执行开始和结束
  4. }
  5. int b = 20; // 全局变量,作用域整个程序,生命周期整个程序

在上述示例中,a 的作用域仅限于 fun 函数,其生命周期也在函数执行期间。而 b 的作用域是整个程序,生命周期也是从程序启动到程序结束。

作用域限定了变量能被使用的范围,而生命周期决定了变量存在的时间跨度,作用域在一定程度上会反映和影响变量的生命周期。

2、static 和 extern

static 和 extern 都是C语⾔中的关键字。

static 是静态的的意思,可以用来:

  • 修饰局部变量
  • 修饰全局变量
  • 修饰函数

extern 是用来声明外部符号的。

2.1 static 修饰局部变量:

代码1:不含static 

  1. void test()
  2. {
  3. int a = 5;
  4. a++;
  5. printf("%d ", a);
  6. }
  7. int main()
  8. {
  9. int i = 0;
  10. for (i = 0; i < 6; i++)
  11. {
  12. test();
  13. }
  14. return 0;
  15. }

该代码的结果会是多少呢?来一起看一下

欸,6个6,怎么得到的呢?

在上述代码中,test 函数内部定义的变量 a 是一个局部变量。

每次调用 test 函数时,都会为 a 分配新的内存空间,并初始化为 5 。然后 a 自增并打印其值。

在  main 函数的  for循环中,连续调用了 6 次 test 函数。

由于每次调用都是独立的,a 的值都会重新从  5 开始计算,然后自增到 6 并打印。

所以会连续打印出 6个6 。

代码2:含static 

  1. void test()
  2. {
  3. static int a = 5;//加上static
  4. a++;
  5. printf("%d ", a);
  6. }
  7. int main()
  8. {
  9. int i = 0;
  10. for (i = 0; i < 6; i++)
  11. {
  12. test();
  13. }
  14. return 0;
  15. }

该代码的结果又会是什么呢?

现在的结果变为了6 7 8 9 10 11。为什么呢?

好像这里每一次调用函数后a产生的值没有被刷新,当下一次调用的时候,会继续使用上一次留下来的值。也就是说进来的a不会再重新创建。

为什么呢?我们可以通过对比来理解static的作用

代码1的test函数中的局部变量i是每次进入test函数先创建变量(生命周期开始)并赋值为0,然后 ++,再打印,出函数的时候变量⽣命周期将要结束(释放内存)。

代码2中,我们从输出结果来看,i的值有累加的效果,其实test函数中的i创建好后,出函数的时候是 不会销毁的,重新进⼊函数也就不会重新创建变量,直接上次累积的数值继续计算。

我们知道内存被划分为栈区,堆区,和静态区

分别存放的东西:

栈区:局部变量、形式参数

堆区:动态内存分配,malloc,calloc,realloc等函数

静态区:全局变量,静态变量

结论:static修饰局部变量改变了变量的生命周期,生命周期改变的本质是改变了变量的存储类型,本来⼀个局部变量是存储在内存的栈区的,但是被 static 修饰后存储到了静态区。存储在静态区的变量和全局变量是一样的,生命周期就和程序的生命周期⼀样了,只有程序结束,变量才销毁,内存才回收。但是作用域不变的。

也就是说被static修饰的局部变量会增长生命周期,即使出了作用域,也不会被销毁

当a被声明为static时,它具有以下特点:

  1. 只会被初始化一次。
  2. 在函数调用之间,其值会被保留。

注意:static修饰的变量是可以被改变的。

2.2  static 修饰全局变量(包含extern的作用):

首先,我们现在add.c文件定义一个全局变量int g_val = 2024;

然后再xu.c中使用全局变量intg_val

结果展示:

哎,为什么打印不出来呢?

这时候我们需要给代码做一点小小的改变,我们再int main()上面加上一行代码

extern int g_val; 这时候我们再来看一下

没有报错,成功打印了。

从上面对比你知道extern的作用了吗?

extern 是用来声明外部符号的,如果⼀个全局的符号在A文件中定义的,在B文件中想使用,就可以使用extern进行声明,然后使用。

如果我们用static来修饰全局变量会产生什么影响呢?来看一下

我们可以发现,原来可以运行的程序由于用static修饰int g_val无法运行了,这是为什么呢?

这就是static修饰全局变量的作用:

使用static修饰全局变量,会使得被static修饰的全局变量只能在本源文件内使用,不能在其他源文件内使用。

结论:

⼀个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。本质原因是全局变量默认是具有外部链接属性的,在外部的文件中想使用,只要适当的声明就可以使用;但是全局变量被 static 修饰之后,外部链接属性就变成了内部链接属性,只能在自己所在的源文件内部使用了,其他源文件,即使声明了,也是无法正常使用的。

所谓的外部链接属性,就是可以跨文件使用。

使用建议:如果⼀个全局变量,只想在所在的源文件内部使用,不想被其他文件发现,就可以使用static修饰。

2.3 static修饰函数:

static修饰函数与修饰全局变量非常相似。

当使用extern声明add(int x, int y)后,图中函数add(int x, int y)能否使用呢?

肯定是可以的,但是,当我们使用static修饰函数add(int x, int y)后,程序是否还能运行成功吗?

不能正常运行。所以static修饰函数后,函数也就不能跨文件使用了。

static 修饰函数和 static 修饰全局变量是一模一样的,一个函数在整个工程都可以使用, 被static修饰后,只能在本⽂件内部使用,其他文件无法正常的链接使用了。 


结语:

本篇文章将告一段落,这篇文章主要讲了两个关键字static 和 extern的作用以及用法

同时还介绍了两个名词作用域与生命周期,在介绍static的用法中,使用了将代码放在多个文件的用法,明天会更新将代码拆分放在多个文件的操作,期待大家的到来!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/937816
推荐阅读
相关标签
  

闽ICP备14008679号