【C语言】详解static和extern关键字

文章目录

  • [1. 前言](#1. 前言)
  • [2. 作用域和生命周期](#2. 作用域和生命周期)
    • [2.1 作用域](#2.1 作用域)
      • [2.1.1 全局变量和局部变量](#2.1.1 全局变量和局部变量)
    • [2.2 生命周期](#2.2 生命周期)
  • [3. static关键字](#3. static关键字)
    • [3.1 static修饰的局部变量](#3.1 static修饰的局部变量)
  • [4. extern关键字](#4. extern关键字)
  • [5. extern和static关键字的相互作用](#5. extern和static关键字的相互作用)
    • [5.1 static修饰函数](#5.1 static修饰函数)
  • 6.总结

1. 前言

可能在你遇到这篇文章之前,你可能并未听过C语言中还有staticextern这两个关键字。或者你也许听过但是并未使用过。

这些都不是问题,在本文中,我将细细的给大家揭晓这两个关键字背后的秘密,及以后我们该如何使用它们。🥇🥇😊

2. 作用域和生命周期

再讲staticextern这两个关键字之前,有必要先给大家讲一下变量的作用域和生命周期。

2.1 作用域

作用域是个什么东东?

顾名思义,作用域就是变量能够作用的范围。换句话说,就是变量能够在这个范围内生效,出了这个范围之后,变量就不起作用了。
这就又引发出一个问题:这个所谓的"范围"在代码中如何界定?

界定的方法:是以一个 {} 为 标志,每一个{}就代表着一个作用域。

听到这里,你可能还是一头雾水。下面我就给几个例子,让你感受到作用域带来的魅力!

我们稍微再修改一下(就是在变量a后面加一个花括号并在里面写一点内容):

那如果我们在图示花括号后面,要打印一个变量b的值,程序还能正确运行吗?

可以看到,编译器给我们报的错误:"b"未声明的标识符。这也就说明了,这个范围已经超出了变量b的作用域了,因此编译器才无法识别出变量b。

通过上述的例子,我相信大家已经对作用域的概念已经深刻的理解了。

2.1.1 全局变量和局部变量

既然都讲到了作用域,那就必须得聊一下全局变量和局部变量了。

变量按照作用域进行分类,可以分为全局变量和局部变量。

全局变量:拥有整个项目工程的作用域。换句话说,就是它能够在整个代码文件中都有效。全局变量是存储在内存的静态区。

局部变量:拥有在该范围内的作用域,出了这个范围该变量就失去作用了。局部变量是存储在内存的栈区的。

注意:全局变量应尽量少地在编程的过程中使用。因为,全局变量所带来地不可控的因素太多了,比较容易错误的使用。

那我们该如何在代码中,识别出哪个变量是全局变量还是局部变量呢?

很简单,仔细观察上面的代码,可以看到,全局变量是写在main函数外部的。

所以,我们可以由此得到一个结论:全局变量是出现在main函数的外部的,局部变量是出现在函数内部(包括自定义函数、库函数等)的变量。

另外,再向大家声明一个点:

在我们初步学习变量的命名规则时,里面规定:变量的命名是不能重复的。这里我拓展一个点就是,此条件是在同一个作用域下才生效。

可能有的读者已经get到我的点了。

你不是说这个条件是在同一个作用域下才生效的麻,也就说明了在不同作用域下我可以使用相同的变量名。

那么,如果我全局变量和局部变量都用同一个变量名时,编译器又该如何接招呢

答案是:局部变量优先。换句话说,在局部变量所处的作用域中,用该局部变量的值,而不是全局变量。

下面我就写一段代码,验证我们的猜想:

c 复制代码
#include<stdio.h>
int a = 88;

int main()
{
	int a = 66;
	printf("%d\n", a); //打印a的值为66
	return 0;
}

结果是:

可以看到,打印出来的值是66,而不是88。这就正是验证了我们的猜想是正确的。

2.2 生命周期

所谓的生命周期就更容易理解了,它就是:

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

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

3. static关键字

static关键字修饰的变量我们称它为静态变量

static关键字的作用:改变变量的生命周期,使之拥有全局变量的生命周期。(但是注意一点,这样的操作并未改变变量的作用域)

那我们说的到底对不对,下面我就写代码,来探讨一下这个问题:

3.1 static修饰的局部变量

可以看到,含有static修饰变量似乎有种记忆能力,它给我们的一种感觉就是能够在之前操作的结果基础上继续进行操作。

对⽐代码1和代码2的效果,你就能理解 static 修饰局部变量的意义。

  • 代码1的test函数中的局部变量i是每次进⼊test函数先创建变量(⽣命周期开始)并赋值为0,然后
    ++,再打印,出函数的时候变量⽣命周期将要结束(释放内存)。
  • 代码2中,我们从输出结果来看,i的值有累加的效果,其实 test函数中的i创建好后,出函数的时候是
    不会销毁的,重新进⼊函数也就不会重新创建变量,直接上次累积的数值继续计算。

使用建议 :未来⼀个变量出了函数后,我们还想保留值,等下次进⼊函数继续使⽤,就可以使⽤static

修饰。

4. extern关键字

extern关键字的作用:赋予变量外部链接属性。

什么是外部链接?

这个问题通常会出现在这么一个场景中,就是我们在大型程序编写中,我们都会将程序的代码划分为多个.c文件,这样做的目的不仅可以增加代码的可读性,还可以提高团队的编程效率。那我们现在假设有个A文件和B文件,A文件的内容和B文件的内容是不能相互使用(相信这个点,大家在编程时都知道),如果强行使用,编译器就会报出错误。

那么现在我接受到了一个任务:我必须要在文件B中使用文件A的内容(一些变量的值、函数等等)。

那我们该怎么做?

用extern关键字。

在展示代码之前,想跟大家聊一聊,为什么就是用这个关键字?

对于文件A来说,文件B是属于外部文件。那么对于文件B来说,文件A里面的内容就属于外部内容。试想一下,两个毫不相干的东西想要相互使用双方的内容,那就必须得建立一个桥梁(链接)。而这个桥梁能够让文件A能够使用文件B的内容,建立桥梁的操作就是在建立外部链接属性。extern在这方面就是专业对口的。

在下面就举个例子:

首先在用这个关键字时,至少得创建两个或两个以上的.c文件。在本例中,创建两个.c文件。

在test1.c的内容:

c 复制代码
int a = 66;

在test.c的内容:

c 复制代码
#include<stdio.h>
extern int a;//这里的变量名必须与test1.c中你想引用的变量名得是一致的
int main()
{
	printf("a = %d\n", a);
	return 0;
}

5. extern和static关键字的相互作用

上面的例子如果你看懂的话,那就太好了。我们继续突发奇想地改造上述的代码。

我们这样改造:

将test1.c中的变量变为静态变量

c 复制代码
static int a = 66;

再编译会出现什么情况?

😲😲😲既然改了一下代码就报错了,这是什么原因呢?

就是static和extern关键字相互作用的结果。

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

使⽤建议:如果⼀个全局变量,只想在所在的源⽂件内部使⽤,不想被其他⽂件发现,就可以使⽤

static修饰。

5.1 static修饰函数

相信初学C语言的读者们可能都没有看过这种写法,static竟然还能修饰函数。

情况一:
在test1.c中的内容:

c 复制代码
int Add(int x, int y)
{
	return x + y;
}

在test.c中的内容:

c 复制代码
#include<sdtio.h>
extern int Add(int x, int y);
int main()
{
	printf("%d\n",Add(2,3));
	return 0;
}

注意,在Add函数形参这部分,可以不用专门写x和y,只写类型也可以。

情况二:

在test1.c内容中:

c 复制代码
static int Add(int x, int y)
{
	return x + y;
}

在test.c内容中:

c 复制代码
#include<sdtio.h>
extern int Add(int x, int y);
int main()
{
	printf("%d\n",Add(2,3));
	return 0;
}

再看看和之前的代码有什么不同?

发现代码直接报错了。

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

本质是因为函数默认是具有外部链接属性,具有外部链接属性,使得函数在整个工程中只要适当的声
明就可以被使用。但是被 static 修饰后变成了内部链接属性,使得函数只能在自己所在源文件内部
使用。

使⽤建议 :⼀个函数只想在所在的源⽂件内部使⽤,不想被其他源⽂件使⽤,就可以使⽤ static 修

饰。

6.总结

在本文中,介绍了变量的作用域和生命周期,还说明了static和extern两个关键字以及它们如何使用。

希望能帮到大家。

文章创作不易,如果你觉得写得好不错的话,请不要吝啬你们的点赞和收藏哦!!!🙏🙏🙏

相关推荐
k093311 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯19 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
Themberfue21 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
plmm烟酒僧23 分钟前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
EricWang135832 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
测试界的酸菜鱼34 分钟前
Python 大数据展示屏实例
大数据·开发语言·python
我是谁??34 分钟前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
时差95336 分钟前
【面试题】Hive 查询:如何查找用户连续三天登录的记录
大数据·数据库·hive·sql·面试·database
让学习成为一种生活方式38 分钟前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
Mephisto.java38 分钟前
【大数据学习 | kafka高级部分】kafka中的选举机制
大数据·学习·kafka