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

时间:2015-10-08 15:24:01

标签: fortran gfortran intel-fortran

守则

以下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)不编译?

2 个答案:

答案 0 :(得分:5)

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

所以,我不会证明代码没有错误(并且gfortran不允许拒绝它),但是让我们来看看发生了什么。

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

  

具有依赖于变量值的维度的数组的声明,例如a(N,3),要求在编译时知道(或至少可知)变量的值。

显式形状数组的边界不必总是由常量表达式给出(我们松散地定义为“在编译时已知/可知”):在某些情况下,显式形状数组可以具有变量给出的界限。这些被称为自动对象(以及规范表达式给出的界限)。

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

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

首先,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是正确的(我们已经错过了一些隐藏得很好的约束)来拒绝第一个代码,它要么在不拒绝其他代码时非常不一致,要么约束真的很奇怪。

答案 1 :(得分:1)

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

这一行

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

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

具有依赖于变量值的维度的数组的声明,例如a(N,3),要求在编译时知道(或至少可知)变量的值。在这种情况下,在主机范围内提供n,属性parameter可以解决问题。虽然它并没有解决这个糟糕的设计 - 但是OP的手似乎与这一点有关。

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

我只提供这个半生不熟的解释,因为经验告诉我,一旦我做了一个真正的Fortran专家(IanH,francescalus,(通常)VladimirF)会因为发布更正而感到愤怒,我们&# 39;所有人都学到了什么。