Fortran 中虚拟参数显式形状数组的声明

Declaration of dummy argument explicit shape arrays in Fortran

我认为在子程序中指定一个显式形伪参数数组可以涉及任何整数变量,包括其他伪变量(通常情况)、模块变量和本子程序的局部变量。但事实证明局部变量(不是虚拟变量)不能在规范中使用。

举例如下:

module mp
implicit none
contains
  subroutine p(b)
    integer :: m=4, n=4 !not integer,parameter :: m=4, n=4
    integer :: b(m,n)
  end subroutine p
end module mp

gfortran 将提高 Error: Variable 'm' cannot appear in the expression at (1)

对于这个例子,我可以使用 integer,parameter :: m=4, n=4 来避免这种情况,但我不明白为什么原来的情况不起作用,考虑到显式形状数组的 bounds/extents 不起作用需要在编译时知道。上述示例的修改版本有效:

module mp
implicit none
integer :: m=4, n=4
contains
  subroutine p(b)
    integer :: b(m,n)
  end subroutine p
end module mp

考虑到两个例子之间的细微差别,我希望它们都能工作,但实际上前者没有。有人能解释一下原因吗?

更新:我发现这是一个非常微妙的问题,因为它取决于子程序是包含在模块中还是独立的,它还取决于gfortran的版本。我在回答区发了例子。

形式上,对这种显式形状数组的边界是什么有要求。这些不只是映射到 "don't have to be known at compile time".

对于数组显式形状,数组边界必须是规范表达式。通常,这样的边界必须是 常量表达式 ,但虚拟参数不是这种情况。这部分导致了(错误的)想法,即它们不需要在编译时知道。

但是,仍然必须满足规范表达式的约束。这些可以在 Fortran 2018 10.1.11 中找到。特别是,局部变量(即使是已保存的变量)可能不会出现在规范表达式中。

对于问题的示例,使用命名常量,例如 with

integer, parameter :: m=4, n=4

允许出现在规范表达式中。实际上,规范表达式 mn 在这种情况下甚至是常量表达式。

如果我们有

function p(b,m,n)
  integer m, n, b(m,n)
end function

然后我们有数组边界的有效规范表达式,即使 mn 不是常量。

最后,我发现这是一个很微妙的问题,因为它取决于gfortran的版本,也取决于子程序是包含在模块中还是独立的。 gfortran-4.8 和 gfortran-8 都不能编译成功以下代码:

module mp3
contains
  subroutine p(b)
    implicit none
    integer :: m=4, n=4 
    integer :: b(m,n)
 end subroutine p
end module mp3

但是如果我们考虑一个独立的子程序如下:

 subroutine p(b)
    implicit none
    integer :: m=4, n=4 
    integer :: b(m,n)
 end subroutine p

然后gfortran-4.8仍然拒绝这个表单,但是gfortran-8接受这个,这可能只是gfortran-8中的一个错误,因为进一步的测试(由user5713492)表明gfortran-8.1.0 也拒绝这种形式。

综上所述,伪参数数组的规范表达式中不允许使用子程序的局部变量。

通常不需要在规范表达式中使用局部 non-constant 变量。所以禁止这种用法并不是一个糟糕的主意。

正确的解决方法是将过程主体放在 BLOCK 结构中:

module mp3
contains
  subroutine p(b)
    implicit none
    integer :: m=4, n=4 
BLOCK
    integer :: b(m,n)
END BLOCK
 end subroutine p
end module mp3

它在 gfortran-8 中作为一个独立的子程序工作的事实应该在 bugzilla 上报告。你有一个很好的最小例子。

编辑:我没有注意到 b 是一个伪参数。我更多的是考虑

module mp3
contains
  subroutine p(x)
    implicit none
    real x
    integer :: m=4, n=4 
BLOCK
    integer :: b(m,n)
END BLOCK
 end subroutine p
end module mp3

但正如示例所示,BLOCK 方法是行不通的。 gfortran 8.1.0 也拒绝带有独立子例程的表单:

  subroutine p(x)
    implicit none
    real x
    integer :: m=4, n=4 
    integer :: b(m,n)
 end subroutine p

Error: Variable 'm' cannot appear in the expression at (1)

(应该如此)