【问题标题】:Declaration of dummy argument explicit shape arrays in Fortran在 Fortran 中声明虚拟参数显式形状数组
【发布时间】:2019-05-24 00:14:36
【问题描述】:

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

一个例子如下:

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 的版本。我已经在答案区域发布了示例。

【问题讨论】:

    标签: arrays fortran gfortran


    【解决方案1】:

    形式上,对于这种显式形状数组的边界是有要求的。这些不只是映射到“不必在编译时知道”。

    对于数组显式形状,数组边界必须是规范表达式。通常,这样的边界必须是常量表达式,但对于虚拟参数则不是这样。这在一定程度上引起了(错误的)想法,即在编译时不需要知道它们。

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

    【讨论】:

    • 我还是不明白为什么会有这个约束(局部变量不能出现在规范表达式中)。这种约束似乎是不一致的。从模块中的局部变量可以在规范表达式中使用这一事实,从逻辑上我们应该推断本子程序的局部变量也可以在规范表达式中使用。
    • 请注意,一个模块变量不能在规范表达式中用于另一个模块变量的边界。模块变量可以在模块子程序中用作规范表达式,因为给定的部分明确允许它。现在,无论是直觉还是必要......
    • 您的第一句话似乎混淆了几件事。模块永远不能在其规范表达式中包含任何具有未知变量的数组。
    • 这是没有矛盾的一点:我们不能在该子例程的规范表达式中使用子例程的局部变量,就像我们不能在另一个模块的规范表达式中使用模块变量一样变量。
    • 模块变量确实可以在规范表达式中使用(被使用或与主机相关联)。根据给定的规则,这是明确允许的。我无法说明标准作者允许这样做的动机,但这显然是故意的(无论人们是否认为它是一致的)。
    【解决方案2】:

    正确的解决方法是将过程主体放在 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
    

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

    编辑:我没有注意到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)
    

    (应该如此)

    【讨论】:

    • 此解决方法不起作用(使用gfortran-8 测试:Error: Symbol ‘b’ at (1) has no IMPLICIT type)。它不起作用的原因也很明显:数组b(m,n)是在本地范围内定义的,与伪参数数组b无关
    • 感谢指正。我没有注意到 b 是一个伪参数。
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-17
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 2018-09-14
      • 1970-01-01
      • 2021-02-21
      相关资源
      最近更新 更多