0

我了解范围和生命周期是什么以及它们有何不同:

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

Lifetime:变量的值将在内存中保留多长时间

我的问题是:在下图中,我们根据什么决定变量 x 有生命周期而不是作用域,而变量 b1 有作用域但没有生命周期?

在此处输入图像描述

4

2 回答 2

1

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

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

于 2018-03-06T14:08:39.503 回答
0

[这个问题用 Java 和 C 标记。这个答案针对 C。这里的信息取自 C 2011 标准的草案 N1570。]

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

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

对于一个变量,它的标识符的范围是由它的声明在源代码中的位置决定的?

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

除了变量标识符之外,还有其他标识符。函数标识符规则;结构、联合和枚举的标签;和 typedef 名称与变量标识符相同。对于标签(在goto语句中使用,写为label:),标识符具有函数作用域,并且在它出现的函数中随处可见。

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

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

  • 如果使用 声明标识符extern,则链接取决于是否已经存在可见的先前声明:

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

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

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

  • 如果一个函数声明时没有存储类说明符(typedefexternstatic_Thread_localautoregister),则它的链接就像是用声明的一样extern(因此它遵循上面关于依赖于先前声明的规则)。

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

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

现在我们可以说明存储期限的规则:

  • 如果一个对象声明了有static和没有_Thread_local,它有静态存储持续时间,它的生命周期是程序的整个执行过程。

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

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

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

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

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

于 2018-03-06T14:12:43.350 回答