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

目录

1、作用域与生命周期

[1.1 作用域](#1.1 作用域)

[1.2 生命周期](#1.2 生命周期)

[1.3 变量的作用域和生命周期之间的关系](#1.3 变量的作用域和生命周期之间的关系)

[2、static 和 extern](#2、static 和 extern)

[2.1 static 修饰局部变量:](#2.1 static 修饰局部变量:)

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

[2.3 static修饰函数:](#2.3 static修饰函数:)

结语:


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


1、作用域与生命周期

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

1.1 作用域

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

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

该怎么理解呢?举个例子

int main()
{
	{
		int a = 10;
		printf("a1 = %d\n", a);
	}
	    printf("a2 = %d\n", a); 
	return 0;
}

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

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

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

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

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

int a = 10;//全局变量
void test()//子函数
{
	printf("a3 = %d\n", a);
}
int main()//主函数
{
	{
		printf("a1 = %d\n", a);
	}
	    printf("a2 = %d\n", a); 
	return 0;
}

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

1.2 生命周期

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

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

这个该怎么理解呢?

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

int main()
{
	{
		int a = 10;
		printf("a1 = %d\n", a);
	}
	    printf("a2 = %d\n", a); 
	return 0;
}

图解:

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

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

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

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

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

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

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

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

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

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

例如:

void fun() 
{
    int a = 10;  // 局部变量,作用域在 fun 函数内,生命周期随函数执行开始和结束
}

int b = 20;  // 全局变量,作用域整个程序,生命周期整个程序

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

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

2、static 和 extern

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

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

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

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

2.1 static 修饰局部变量:

代码1:不含static

void test()
{
	int a = 5;
	a++;
	printf("%d ", a);
}
int main()
{
	int i = 0;
	for (i = 0; i < 6; i++)
	{
		test();
	}
	return 0;
}

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

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

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

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

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

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

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

代码2:含static

void test()
{
	static int a = 5;//加上static
	a++;
	printf("%d ", a);
}
int main()
{
	int i = 0;
	for (i = 0; i < 6; i++)
	{
		test();
	}
	return 0;
}

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

现在的结果变为了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的用法中,使用了将代码放在多个文件的用法,明天会更新将代码拆分放在多个文件的操作,期待大家的到来!!!

相关推荐
今天我又学废了6 分钟前
Scala学习记录,List
学习
幸运超级加倍~10 分钟前
软件设计师-上午题-16 算法(4-5分)
笔记·算法
杨荧11 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
白子寰17 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
王俊山IT30 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。32 分钟前
c++多线程
java·开发语言
小政爱学习!34 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯1 小时前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
Themberfue1 小时前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·