Java 如何确定变量是否具有作用域和生存期?

Java 如何确定变量是否具有作用域和生存期?,java,c,scope,lifetime,lifetime-scoping,Java,C,Scope,Lifetime,Lifetime Scoping,我了解什么是范围和生命周期以及它们之间的区别: 范围:变量的可见性,即哪些代码块可以引用该变量 生存期:变量值将在内存中保留多长时间 我的问题是:,在什么基础上我们决定变量x有生存期而不是作用域,变量b1有作用域但没有生存期 在C示例中,static关键字将变量x保留在内存中,以备将来调用函数。但这并不意味着您可以从该函数外部访问x(就像它在main中所做的那样)。因此,内存中有一个变量(生存期),但无法从函数外部访问它(无作用域) 在java示例中,声明了一个对象引用,但从未创建任何对象。因此

我了解什么是范围和生命周期以及它们之间的区别:

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

生存期:变量值将在内存中保留多长时间

我的问题是:,在什么基础上我们决定变量x有生存期而不是作用域,变量b1有作用域但没有生存期


在C示例中,
static
关键字将变量
x
保留在内存中,以备将来调用函数。但这并不意味着您可以从该函数外部访问
x
(就像它在
main
中所做的那样)。因此,内存中有一个变量(生存期),但无法从函数外部访问它(无作用域)


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

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

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

标识符总是有一些作用域,对象总是有一些生存期。(当使用
malloc
分配内存时,存储有生存期,但没有标识符,因此没有名称的作用域。)

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

  • 如果声明在任何块(在“{”和“}”内的一系列语句和声明)之外,则它具有文件作用域,并且标识符从声明到翻译单元的末尾都是可见的(预处理完成后的源代码)
  • 如果声明位于块内或函数定义的参数声明内(不仅仅是声明),则它具有块作用域,并且标识符从其声明到块的末尾都是可见的
  • 如果该声明位于不是定义的函数声明的参数声明内,则它具有函数原型作用域,并且从其声明到函数声明器的结尾都可见
除了变量标识符之外,还有其他标识符。函数标识符的规则;结构、联合和枚举的标记;和typedef名称与变量标识符的名称相同。对于标签(在
goto
语句中使用,写为
label:
),标识符具有功能范围,并且在其出现的函数中随处可见

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

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

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

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

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

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

  • 如果函数声明时没有存储类说明符(
    typedef
    extern
    static
    \u Thread\u local
    auto
    ,或
    register
    ),其链接就好像是用
    extern
    声明的一样(因此它遵循上面关于依赖于先前声明的规则)

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

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

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

  • 如果使用
    static
    声明对象,而不使用
    \u Thread\u local
    声明对象,则该对象具有静态存储持续时间,其生存期是程序的整个执行过程

  • 如果声明的对象没有
    \u Thread\u local
    ,并且具有外部或内部链接,则该对象具有静态存储持续时间

  • 如果使用
    \u Thread\u local
    声明对象,则该对象具有线程存储持续时间,其生存期是为其创建的线程的整个执行过程

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

对于由
mallo中的例程创建的对象,也有一个分配的存储持续时间