如何确定变量是否具有范围和生命周期?

时间:2018-03-06 14:04:07

标签: java c scope lifetime lifetime-scoping

我了解范围和生命周期以及它们之间的差异:

范围:变量的可见性,即哪些代码块可以引用该变量

终身:变量的值将如何在内存中保留

我的问题是:in the picture below,我们在什么基础上决定变量x有生命周期而不是范围,变量b1有范围但没有生命周期?

enter image description here

2 个答案:

答案 0 :(得分:1)

在C示例中,static关键字将变量x保留在内存中以供将来的函数调用。但这并不意味着您可以从该功能外部访问x(就像它在main中尝试的那样)。所以你在内存中有一个变量(生命周期),但不能从函数外部访问它(没有范围)

在java示例中,声明了一个对象引用,但是没有创建任何对象。所以你可以访问引用(你有范围)但内存中没有对象(没有生命周期)

答案 1 :(得分:0)

[这个问题用Java和C标记。这个答案解决了C.这里的信息来自C 2011标准的N1570草案。]

变量由标识符(知道它的名称)和对象(内存中保存其值的存储)组成。

标识符总是有一些范围,对象总是有一些生命周期。 (当内存分配有malloc时,存储具有生命周期,但没有标识符,因此没有名称的范围。)

对于变量,其标识符的范围由其声明在源代码中的位置确定?

  • 如果声明在任何块之外(一系列声明和声明在' {'和'}')内,它具有文件范围 ,从声明到翻译单元末尾可以看到标识符(预处理完成后的源代码)。
  • 如果声明在一个块内或在函数定义的参数声明内(不仅仅是一个声明),它有块范围,并且标识符从其声明到结尾可见块。
  • 如果声明在函数声明的参数声明中不是定义,则它具有函数原型作用域,并且从声明到函数声明符的末尾是可见的。

除变量标识符外还有其他标识符。功能标识符规则;结构,联合和枚举的标签;和typedef名称与变量标识符相同。对于标签(在goto语句中使用,写为label:),标识符具有函数范围,并且在它出现的函数中的任何位置都可见。

有四个存储持续时间,也称为生命周期:静态线程自动已分配。对象的存储持续时间受其标识符链接的影响,因此我们需要先讨论链接。链接是一种使不同范围内的相同标识符引用同一对象的方法。

  • 如果使用static声明了文件范围内的对象或函数的标识符,则它具有内部链接。内部链接意味着同一翻译单元中的任何其他声明将引用相同的对象或功能。

  • 如果使用extern声明标识符,则链接取决于是否已显示先前的声明:

    1. 如果没有先前的声明可见,则标识符具有外部链接。这意味着程序中的任何其他声明都将引用相同的对象或函数。

    2. 如果有先前的声明,并且它指定了内部或外部链接,则当前声明的链接与先前的声明相同。

    3. 如果有先前的声明,但没有指定任何链接,则当前声明的链接是外部的。

  • 如果声明的函数没有存储类说明符(typedefexternstatic_Thread_localauto或{ {1}}),它的链接就像是用register声明的那样(所以它遵循上面关于先前声明的规则)。

  • 如果在没有存储类说明符的文件范围内声明对象,则其链接是外部的。

  • 否则,标识符具有无链接,因此它的每个声明都引用不同的实体。这包括不是对象或函数的任何内容的标识符(例如结构标记或typedef名称),函数参数以及在没有extern的函数内声明的变量。

现在我们可以说明存储持续时间的规则:

  • 如果一个对象声明为extern且没有static,则它具有静态存储持续时间,其生命周期是整个程序的执行。< / p>

  • 如果声明的对象没有_Thread_local并且具有外部或内部链接,则它具有静态存储持续时间。

  • 如果使用_Thread_local声明对象,则它具有线程存储持续时间,并且其生命周期是创建该线程的线程的整个执行。

  • 如果声明的对象没有_Thread_local且没有链接,则它具有自动存储持续时间。如果它不是一个可变长度数组,那么它的生命周期是从执行进入该块时开始,直到执行该块结束。 (注意,调用一个函数会挂起块的执行但不会结束它。)如果它是一个可变长度数组,它的生命周期是从执行到达声明时直到执行离开声明的范围。

static系列中的例程创建的对象还有分配的存储持续时间,并且有一个临时生命周期适用于在其中创建的对象表达式,但我省略了对它们的讨论,因为它们与命名对象的声明无关。

如您所见,规则有些复杂。但是,您将通过练习来认识范围和生命周期。