【每周分享】C语言的作用域和生存期到底是什么?

📅 2026/6/16 3:02:20
【每周分享】C语言的作用域和生存期到底是什么?
在嵌入式C语言开发中我们会经常遇到下面这两个概念作用域Scope生存期Lifetime。其实对于这两个C语言的基本概念应该很多坛友都能多多少少说出一些相关的内容也是嵌入式岗位面试的时候会经常涉及到的笔试题目主要用来描述变量只是角度不同今天就抽空给大家简单总结一下这两个概念的一些基本内容并通过实例进一步说明一下加深我们的印象毕竟把这些基本知识掌握透彻才能进一步领悟C语言的灵魂。一、我们先来看看作用域作用域————“在哪儿能被看见”空间维度所谓作用域其实是很多程序设计语言中非常重要的一个概念主要用于减少命名冲突并提高程序逻辑的局部性以此来提高程序的可靠性和健壮性。通俗一点来讲就是在程序里面的哪些地方可以访问这个变量而在C语言代码中作用域主要是由花括号{ }来决定也就是说如果错误使用不在作用域范围内的变量则可能会出现程序编译错误和程序运行错误等问题。接下来就通过下面几个方向来举例说明这样更好理解。块作用域变量作用域只在花括号内部文件作用域变量作用域包括整个文件同名变量的屏蔽规则内外层变量同名时程序如何决策1、块作用域变量被定义在一对花括号内部即正常情况下只能在花括号内部代码块里面使用这个变量。我们先来看看下面的代码你觉得编译会成功通过吗复制intmain(){intx1;if(x1){inty2;printf(x %d\r\n,x);printf(y %d\r\n,y);}printf(x %d\r\n,x);printf(y %d\r\n,y);return0;}认真想一想如果没看帖子内容之前你也能判断正常吗如果可以那你很棒我们来编译一下果然编译失败编译失败的原因是最后一个通过printf打印变量y的值的时候提示变量y为没有声明的标识符没有定义。原因其实很简单因为变量y是被声明在if所包含的花括号里面的其作用域仅限此花括号内部下面这个是对每条语句的解释复制intmain(){intx 1;// x的作用域从这行开始到main函数结束if(x 1)// y的作用域与if条件的真假没有关系{inty 2;// y的作用域仅限if语句块内部printf(x %d\r\n, x);//没有问题x在外层定义则内层可用printf(y %d\r\n, y);//没有问题y在块内定义块内可用}printf(x %d\r\n, x);//没有问题x在外层定义则外层可用printf(y %d\r\n, y);//有问题y不在其作用域内则外层不可用return0;}// x的作用域到此结束通过以上的详细注释应该理解了为什么会出现这种编译错误了吧。2、文件作用域所谓的文件作用域是指定义在所有函数外部的变量的作用域也就是我们常见的全局变量其作用域一般就是从其定义的位置开始到整个文件一般是C源文件结束都有效。这个相对来说比较好理解也不容易出错不过我们也来看代码理解一下复制intg_test 666;//全部变量作用域为整个源文件voidfunc(void){printf(g_test %d\r\n, g_test);//没有问题文件里面的函数的内部可以访问}intmain(){func();printf(g_test %d\r\n, g_test);//没有问题main函数也可以访问return0;}以上这段代码肯定可以编译通过这个没有异议吧~~我也在代码后面加了注释毕竟还有初入职场和初识C语言的兄弟们。3、同名变量的屏蔽规则所谓的同名变量的屏蔽规则也就是在一段程序里面当内层变量和外层变量出现同一个名称的时候内层变量会自动生效外层变量会自动失效这就是内层变量屏蔽外层变量。用文字来说可能会比较抽象我们还是用代码来解释看下面代码复制intx66;intmain(){intx88;printf(x %d\r\n,x);{intx99;printf(x %d\r\n,x);}printf(x %d\r\n,x);return0;}大家认为这里会打印出什么……再想想……打印结果如下为什么是这个打印这个呢结合代码增加注释如下就明白了原因复制intx 66;//全局变量xintmain(){intx 88;//局部变量x屏蔽了全局xprintf(x %d\r\n, x);//输出局部变量x的值{intx 99;//更内层的局部变量x屏蔽了外层的局部变量xprintf(x %d\r\n, x);//输出内层局部变量x的值}printf(x %d\r\n, x);//退出内层到外层外层局部变量x可见了return0;}二、我们再来看看生存期生存期————“活了多久”时间维度其实生存期的概念类似于作用域只是通过另一种角度来描述变量而已指的是变量在内存中真实存在的时间也就是从分配内存到回收内存的过程。接下来也是通过下面几个方向来举例说明便于理解。静态生存期变量在程序开始运行时即分配内存直到程序结束即释放自动生存期变量在某个代码块里自动分配内存离开代码块时自动释放动态生存期变量被手动申请内存和释放内存存在时间由是否手动释放为准。1、静态生存期所谓静态生存期也就是变量在程序开始运行时就已经被分配内存直到程序结束后才被释放这种主要包括全局变量和静态局部变量。全局变量定义在函数外面默认就是静态生存期静态局部变量static关键词修饰不能省略虽然定义在函数内部但它的值会在函数调用期间一直保留具有静态生存期看下面的代码复制voidcounter(void){staticintcount 0;count;printf(counter被调用了 %d 次\n, count);}intmain(){counter();counter();counter();return0;}程序执行结果从以上执行结果也可以看出静态局部变量count的值确实只是初始化一次其值是保留的每次运行是在上一次值的基础上加1的。静态局部变量的这种特性也使其得到广泛应用可以**上一次值且不影响代码可读性还能增加代码可维护性。2、自动生存期所谓自动生存期就是变量在进入代码块的时候自动分配内存离开代码块的时候自动释放内存比较典型的就是函数内部的局部变量都是自动生存期如下代码注释和执行结果所示复制voidfunc(void){intx 0;// x在这里“出生”x;printf(x %d\n, x);// 总是输出 1}// x在这里“死亡”内存被回收intmain(){func();return0;}所以每次调用函数 func局部变量x 都会重新出生、初始化然后死亡所以输出***是 1虽然看似简单但这种原因引起的Bug有时候还真不容易排查因为你根本不会想到是这种操作出了问题。这里要想实现程序功能将局部变量x改成静态局部变量就可以了。3、动态生存期所谓动态生存期一般是由攻城狮自己手动控制生存期对于C语言而已即通过malloc动态申请内存通过free释放内存。如果不手动释放就会一直存在。如下代码和注释所示复制voidfunc(void){int*p (int*)malloc(sizeof(int));// 申请内存p本身是局部变量指针*p 100;printf(*p %d\r\n, *p);free(p);//释放内存}intmain(){func();return0;}如果没有free(p);这行内存就会一直存在造成内存泄漏; 函数结束指针变量p死亡了但它指向的那块内存依然存在且无法再被访问。以上通过实例详细介绍了C语言里面的作用域和生存期两个用于描述变量的基本概念两者其实是从不同角度描述了变量的行为和作用即作用域问的是“我能在哪用它”生存期问的是“它在内存里面待多久”最后用下面这张简图汇总一下吧现在是不是都非常明白了---------------------作者dffzh链接https://bbs.21ic.com/icview-3508591-1-1.html?_dsign8a498b4a来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。