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

时间:2019-05-24 00:14:37

标签: arrays fortran gfortran

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

一个例子如下:

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来避免这种情况,但是考虑到不需要知道显式形状数组的边界/范围这一事实,我不明白为什么原始案例不起作用在编译时。上面示例的修改版本可以工作:

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

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

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

3 个答案:

答案 0 :(得分:3)

形式上,明确要求显式形状数组的边界是什么。这些不只是映射为“不必在编译时就知道”。

对于数组显式形状,数组边界必须为规范表达式。通常,此类界限必须是恒定表达式,但对于伪参数则不是这种情况。这部分地导致了(错误的)思想,即在编译时不需要知道它们。

但是,仍然必须满足规范表达式的约束。这些可以在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不是常数,我们也具有有效的数组边界指定表达式。

答案 1 :(得分:1)

最后,我发现这是一个非常微妙的问题,因为它取决于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也拒绝此表格。

总之,伪参数数组的规范表达式中不允许子例程的局部变量。

在规范表达式中很少使用局部非常量变量。因此,禁止这种用法并不是一个糟糕的主意。

答案 2 :(得分:1)

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

TypeError: friends[1] is undefined

应该在bugzilla上报告它在gfortran-8中作为独立子例程运行的事实。您那里有一个很好的最小示例。

编辑:我没有注意到console.log()是一个伪参数。我在考虑诸如此类的问题

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

但是,如示例所示,BLOCK方法无法正常工作。同样,gfortran 8.1.0使用独立的子例程拒绝该表单:

b

(应有)