gfortran 和 ifort 之间的编译器差异(可分配数组和全局变量)

Compiler difference between gfortran and ifort (allocatable arrays and global variables)

代码

下面的MWE描述了我想要使用的东西(注意,我没有设计这个,我只是想使用别人的代码,我通常不会使用全局变量)。

PROGRAM MAIN
IMPLICIT NONE

  integer :: N
  real(8), allocatable :: a(:,:)

  N=3
  allocate(a(N,3))

  a=initialize_array()

  CONTAINS
    function initialize_array() result(a)
    IMPLICIT NONE
        real(8) :: a(N,3)
        a=1
    end function initialize_array  

END PROGRAM MAIN

问题

gfortran 给出一个错误,显示为 Error: Variable 'n' cannot appear in the expression at (1),指向函数内部的 real(8) :: a(N,3)。 在子程序中它会工作,那么这里可能是什么问题?

问题

为什么 ifort (v. 15.0.3) 会编译它,而 gfortran (v. 4.8.4) 不会?

我认为这可能是一种解释,尽管像@VladimirF 我实际上无法回忆或找到标准的相关部分(如果有的话)。

这一行

real(8) :: a(N,3)

声明函数的结果是一个名为 a 的数组。这掩盖了通过 主机关联 引用数组 a 的相同名称的可能性。函数范围内的a不是程序范围内的a

维数取决于变量值的数组的声明,例如 a(N,3),要求变量的值在编译时已知(或至少可知)。在这种情况下,在主机范围内提供 n 属性 parameter 可以解决问题。虽然它不能解决糟糕的设计——但 OP 的手似乎在这一点上束手无策。

英特尔编译器编译这个并不让我感到惊讶,为了向后兼容,它编译了它的祖先多年来编译的各种奇怪的东西。

我只提供这个半生不熟的解释,因为经验告诉我,一旦我这样做,一位真正的 Fortran 专家(IanH、francescalus、(通常)VladimirF)就会非常愤怒 post 更正,我们都会学到一些东西。

正如其他人所评论的那样,很难说某些事情是否明确允许:该语言主要基于规则和限制条件。

所以,我不会证明代码没有错误(并且不允许gfortran拒绝它),但让我们看看是怎么回事。

首先,我反对 给出的一件事,因为这有点相关:

The declaration of an array with a dimension dependent on the value of a variable, such as a(N,3), requires that the value of the variable be known (or at least knowable) at compile time.

显式形状数组的边界不需要总是由 常量表达式给出(我们松散地定义为 "known/knowable at compile time"):在某些情况下显式形状数组可以有由变量给出的界限。这些被称为自动对象(以及规范表达式给出的界限)。

函数结果就是这样一个允许自动对象的地方。在函数结果声明的问题示例中,N 与主机关联并形成规范表达式。

与其用尽所有其他约束来查看 a 的声明是否真的被允许,不如让我们看看 gfortran 如何响应程序的小修改。

首先,gfortran 反对的问题代码的精简版本。

  integer n
contains
  function f() result(g)
     real g(n)
  end function f
end program

f 的函数结果名称为 g。我们如何称呼函数结果并不重要,那么当我们称它为 f?

时会发生什么
  integer n
contains
  function f()
     real f(n)
  end function f
end program

这对我来说很愉快。

如果我们在模块而不是主程序中构建第一个块会怎样?

module mod
  integer n
contains
  function f() result(g)
     real g(n)
  end function f
end module

这也编译。

自然的结论:即使 gfortran 拒绝第一个代码是正确的(我们错过了一些隐藏得很好的约束),它要么在不拒绝其他代码方面非常不一致,要么约束真的很奇怪。