包含的子例程中变量和函数的作用域规则

Scoping rules for variable and functions in contained subroutines

我无法理解为什么在子例程中声明的变量 (i) 会出现在包含的子例程中,但对于函数 (fie) 却不是这样,这导致编译错误。我搜索了一个答案,也试图看看我是否能在 Fortran 95 标准中找到一些东西,但没有成功。

我写了一个小示例程序:

program pgm
  call a
end

subroutine a
  implicit none
  integer :: i
  double precision :: fie

  i = 7
  call b
  !write(*,*) fie(9)

contains
  subroutine b
    double precision :: x
    !double precision :: fie

    x = i
    x = x + fie(i)
    write(*,*) x
  end subroutine
end subroutine


double precision function fie(ii)
  implicit none
  integer, intent(in) :: ii

  fie = ii
end function

在 cygwin (gfortran 5.4.0) 下使用 gfortran 编译时,我收到以下错误消息:

$ gfortran aa.f90
aa.f90:20:15:

     x = x + fie(i)
               1
Error: ‘fie’ at (1) is not a function

当启用任一注释行时,程序会正确编译和运行。

我在使用Intel编译器(Intel Fortran 12.1.7.367,确实很老)时看到了类似的错误信息。

看起来 fie 必须在包含的例程中可用,或者必须在包含的子例程中使用,但如前所述,我无法在网上或 Fortran 95 中找到答案标准(或者我没有找合适的词)。

有什么解释吗?

最简单的修复方法是使用

double precision, external :: fie

外部属性(也可以通过external语句指定)表示:这是一个过程,我没有声明局部变量。

要将没有 external 的声明解释为函数声明,函数引用必须存在于函数体内。内部功能不算数。因此,编译器创建了一个名为 fie.

的局部双精度变量

感谢 IanH 提供相关标准规则(来自 Fortran 2008 (16.5.1.4p5),但 Fortran 95 将具有等效规则):

If an external or dummy procedure with an implicit interface is accessed via host association, then it shall have the EXTERNAL attribute in the host scoping unit; if it is invoked as a function in the inner scoping unit, its type and type parameters shall be established in the host scoping unit. The type and type parameters of a function with the EXTERNAL attribute are established in a scoping unit if that scoping unit explicitly declares them, invokes the function, accesses the function from a module, or accesses the function from its host where its type and type parameters are established.

当然,显式接口(最好使用模块)比外部函数要好得多。