我了解范围和生命周期是什么以及它们有何不同:
范围:变量的可见性,即哪些代码块可以引用该变量
生命周期:变量值的长度将如何保留在内存中
我的问题是: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
声明一样(因此它遵循上述规则,取决于先前的声明) 。extern
的函数内声明的变量。现在我们可以说明存储持续时间的规则:
static
并且没有_Thread_local
声明对象,则它具有静态存储持续时间,并且其生命周期是程序的整个执行。_Thread_local
并且具有外部或内部链接,则它具有静态存储持续时间。_Thread_local
声明对象,则它具有线程存储持续时间,并且其生存期是创建的线程的整个执行。static
且没有链接,则它具有自动存储持续时间。如果它不是一个可变长度数组,那么它的生命周期是从执行进入该块时开始,直到执行该块结束。 (注意,调用一个函数会挂起块的执行但不会结束它。)如果它是一个可变长度数组,它的生命周期是从执行到达声明时到执行离开声明的范围。对于由malloc
系列中的例程创建的对象,还有一个已分配的存储持续时间,并且有一个临时生命周期适用于在表达式中创建的对象,但我省略了对它们的讨论,因为它们与命名对象的声明无关。
如您所见,规则有些复杂。但是,您将通过练习来认识范围和生命周期。