Arrays Fortran中伪参数显式形状数组的声明

Arrays Fortran中伪参数显式形状数组的声明,arrays,fortran,gfortran,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

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

例如:

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
 subroutine p(b)
    implicit none
    integer :: m=4, n=4 
    integer :: b(m,n)
 end subroutine p
gfortran将引发
错误:变量“m”不能出现在表达式中的(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的版本。我已经在答案区域发布了示例。

正式地说,对于这种显式形状数组中的边界有一些要求。这些并不是简单地映射到“编译时不必知道”

对于数组显式形状,数组边界必须是规范表达式。通常,此类边界必须是常量表达式,但伪参数的情况并非如此。这在一定程度上导致了一种(错误的)想法,即编译时不需要知道它们

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

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

integer, parameter :: m=4, n=4
在规范表达式中允许。实际上,规范表达式
m
n
在这种情况下甚至是常量表达式

如果我们有

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

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

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

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

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
 subroutine p(b)
    implicit none
    integer :: m=4, n=4 
    integer :: b(m,n)
 end subroutine p
然后,
gfortran-4.8
仍然拒绝此表单,但
gfortran-8
接受此表单,这可能只是
gfortran-8
中的一个错误,因为进一步的测试(由用户5713492)表明,
gfortran-8.1.0
也拒绝此表单

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


通常不需要在规范表达式中使用局部非常量变量。因此,禁止这种用法并不可怕。

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

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上报告。你有一个很好的例子

EDIT:我没有注意到
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
但是,正如示例所示,块方法根本无法工作。此外,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)

(应该如此)

我仍然无法理解为什么会有此约束(局部变量不能出现在规范表达式中)。这个约束似乎不一致。从模块中的局部变量可以在规范表达式中使用这一事实出发,逻辑上我们应该推断当前子例程的局部变量也可以在规范表达式中使用。请注意,模块变量不能在规范表达式中用于另一个模块变量的边界。模块变量可以在模块子程序中用作规范表达式,因为给定的部分明确允许它。现在,无论这是直观的还是必要的…你的第一句话似乎混淆了几件事。模块在其规范表达式中永远不能包含任何具有未知变量的数组。这是不一致的点:我们不能在该子例程的规范表达式中使用子例程的局部变量,就像我们不能在另一个模块变量的规范表达式中使用模块变量一样。模块变量确实可以在规范表达式中使用(使用或主机关联)。根据给出的规则,这是明确允许的。我无法说明标准编写者允许这样做的动机,但这显然是有意的(无论人们是否认为它是一致的)。这种解决方法不起作用(通过使用
gfortran-8
错误:第(1)处的符号“b”没有隐式类型
)。它不起作用的原因也很明显:array
b(m,n)
是在局部范围内定义的,它与伪参数array
b
无关,谢谢您的更正。我没有注意到
b
是一个伪参数。