如何确定变量是否具有范围和生命周期?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何确定变量是否具有范围和生命周期?相关的知识,希望对你有一定的参考价值。
我了解范围和生命周期是什么以及它们有何不同:
范围:变量的可见性,即哪些代码块可以引用该变量
生命周期:变量值的长度将如何保留在内存中
我的问题是:in the picture below,我们在什么基础上决定变量x具有生命周期而不是范围,变量b1具有范围但没有生命周期?
在C示例中,static
关键字将变量x
保存在内存中以供将来的函数调用。但这并不意味着你可以从该函数外部访问x
(就像它试图在main
中那样)。所以你在内存中有一个变量(生命周期)但是不能从函数外部访问它(没有范围)
在java示例中,声明了一个对象引用,但是没有创建任何对象。所以你可以访问引用(你有范围)但内存中没有对象(没有生命周期)
[问题用Java和C标记。这个答案解决了C.这里的信息来自C 2011标准的N1570草案。]
变量由标识符(已知的名称)和对象(内存中保存其值的存储)组成。
标识符总是有一些范围,对象总是有一些生命周期。 (当使用malloc
分配内存时,存储具有生存期,但没有标识符,因此没有名称的范围。)
对于变量,其标识符的范围由其声明在源代码中的位置确定?
- 如果声明在任何块之外('{'和'}'内的一系列语句和声明),它具有文件范围,并且标识符从声明到翻译单元末尾可见(预处理后的源代码)已经完成了)。
- 如果声明在块内或函数定义的参数声明内(不仅仅是声明),它具有块作用域,并且标识符从其声明到块的末尾是可见的。
- 如果声明在函数声明的参数声明中,而不是定义,则它具有函数原型作用域,并且从声明到函数声明符的末尾是可见的。
除变量标识符外还有其他标识符。功能标识符规则;结构,联合和枚举的标签;和typedef名称与变量标识符相同。对于标签(在goto
语句中使用,写为label:
),标识符具有函数范围,并且在它出现的函数中的任何位置都可见。
有四个存储持续时间,也称为生命周期:静态,线程,自动和已分配。对象的存储持续时间受其标识符链接的影响,因此我们需要先讨论链接。链接是一种使不同范围内的相同标识符引用同一对象的方法。
- 如果使用
static
声明对象的标识符或文件范围的函数,则它具有内部链接。内部链接意味着同一翻译单元中的任何其他声明将引用相同的对象或功能。 - 如果使用
extern
声明标识符,则链接取决于是否已有先前声明可见: 如果没有可见的先前声明,则标识符具有外部链接。这意味着程序中的任何其他声明都将引用相同的对象或函数。 如果存在先前声明,并且它指定内部或外部链接,则当前声明的链接与先前声明相同。 如果存在先前声明但未指定任何链接,则当前声明的链接是外部的。 - 如果声明的函数没有存储类说明符(
typedef
,extern
,static
,_Thread_local
,auto
或register
),则其链接就像使用extern
声明一样(因此它遵循上述规则,取决于先前的声明) 。 - 如果在没有存储类说明符的文件范围内声明对象,则其链接是外部的。
- 否则,标识符没有链接,因此它的每个声明都指向不同的实体。这包括不是对象或函数的任何内容的标识符(例如结构标记或typedef名称),函数参数以及在没有
extern
的函数内声明的变量。
现在我们可以说明存储持续时间的规则:
- 如果使用
static
并且没有_Thread_local
声明对象,则它具有静态存储持续时间,并且其生命周期是程序的整个执行。 - 如果声明的对象没有
_Thread_local
并且具有外部或内部链接,则它具有静态存储持续时间。 - 如果使用
_Thread_local
声明对象,则它具有线程存储持续时间,并且其生存期是创建的线程的整个执行。 - 如果声明的对象没有
static
且没有链接,则它具有自动存储持续时间。如果它不是一个可变长度数组,那么它的生命周期是从执行进入该块时开始,直到执行该块结束。 (注意,调用一个函数会挂起块的执行但不会结束它。)如果它是一个可变长度数组,它的生命周期是从执行到达声明时到执行离开声明的范围。
对于由malloc
系列中的例程创建的对象,还有一个已分配的存储持续时间,并且有一个临时生命周期适用于在表达式中创建的对象,但我省略了对它们的讨论,因为它们与命名对象的声明无关。
如您所见,规则有些复杂。但是,您将通过练习来认识范围和生命周期。
以上是关于如何确定变量是否具有范围和生命周期?的主要内容,如果未能解决你的问题,请参考以下文章